diff --git a/third_party/cargo/BUILD.bazel b/third_party/cargo/BUILD.bazel index ba9fadd..2b92789 100644 --- a/third_party/cargo/BUILD.bazel +++ b/third_party/cargo/BUILD.bazel @@ -14,7 +14,7 @@ licenses([ # Aliased targets alias( name = "cgmath", - actual = "//third_party/cargo/vendor/cgmath-0.17.0:cgmath", + actual = "//third_party/cargo/vendor/cgmath-0.18.0:cgmath", tags = [ "cargo-raze", "manual", @@ -41,7 +41,7 @@ alias( alias( name = "image", - actual = "//third_party/cargo/vendor/image-0.23.4:image", + actual = "//third_party/cargo/vendor/image-0.23.12:image", tags = [ "cargo-raze", "manual", @@ -50,16 +50,7 @@ alias( alias( name = "log", - actual = "//third_party/cargo/vendor/log-0.4.8:log", - tags = [ - "cargo-raze", - "manual", - ], -) - -alias( - name = "openvr", - actual = "//third_party/cargo/vendor/openvr-0.6.0:openvr", + actual = "//third_party/cargo/vendor/log-0.4.11:log", tags = [ "cargo-raze", "manual", @@ -68,7 +59,7 @@ alias( alias( name = "vulkano", - actual = "//third_party/cargo/vendor/vulkano-0.18.0:vulkano", + actual = "//third_party/cargo/vendor/vulkano-0.20.0:vulkano", tags = [ "cargo-raze", "manual", @@ -77,7 +68,7 @@ alias( alias( name = "vulkano_win", - actual = "//third_party/cargo/vendor/vulkano-win-0.18.0:vulkano_win", + actual = "//third_party/cargo/vendor/vulkano-win-0.20.0:vulkano_win", tags = [ "cargo-raze", "manual", @@ -86,7 +77,7 @@ alias( alias( name = "winit", - actual = "//third_party/cargo/vendor/winit-0.22.2:winit", + actual = "//third_party/cargo/vendor/winit-0.24.0:winit", tags = [ "cargo-raze", "manual", diff --git a/third_party/cargo/Cargo.lock b/third_party/cargo/Cargo.lock index 8401c62..847312f 100644 --- a/third_party/cargo/Cargo.lock +++ b/third_party/cargo/Cargo.lock @@ -1,45 +1,50 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] -name = "adler32" -version = "1.0.4" +name = "ab_glyph_rasterizer" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff" + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "andrew" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" +checksum = "8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf" dependencies = [ "bitflags", - "line_drawing", - "rusttype 0.7.9", + "rusttype", "walkdir", "xdg", "xml-rs", ] -[[package]] -name = "android_log-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" - [[package]] name = "approx" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" dependencies = [ "num-traits", ] @@ -52,20 +57,14 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "autocfg" -version = "0.1.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" @@ -81,9 +80,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bytemuck" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431" +checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac" [[package]] name = "byteorder" @@ -93,20 +92,19 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "calloop" -version = "0.4.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160" +checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" dependencies = [ - "mio", - "mio-extras", - "nix", + "log", + "nix 0.18.0", ] [[package]] name = "cc" -version = "1.0.54" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cfg-if" @@ -115,44 +113,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] -name = "cgmath" -version = "0.17.0" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cgmath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" dependencies = [ "approx", "num-traits", - "rand", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "cmake" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" -dependencies = [ - "cc", ] [[package]] name = "cocoa" -version = "0.19.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" +checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8" dependencies = [ "bitflags", "block", - "core-foundation 0.6.4", - "core-graphics 0.17.3", + "core-foundation 0.7.0", + "core-graphics 0.19.2", "foreign-types", "libc", "objc", @@ -160,14 +145,30 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.20.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f7b6f3f7f4f0b3ec5c5039aaa9e8c3cef97a7a480a400fd62944841314f293d" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" dependencies = [ "bitflags", "block", - "core-foundation 0.7.0", - "core-graphics 0.19.0", + "cocoa-foundation", + "core-foundation 0.9.1", + "core-graphics 0.22.2", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.1", + "core-graphics-types", "foreign-types", "libc", "objc", @@ -175,9 +176,9 @@ dependencies = [ [[package]] name = "color_quant" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "compile_with_bazel" @@ -188,21 +189,17 @@ dependencies = [ "flatbuffers", "image", "log", - "openvr", + "nix 0.19.1", "vulkano", "vulkano-win", "winit", ] [[package]] -name = "core-foundation" -version = "0.6.4" +name = "const_fn" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -dependencies = [ - "core-foundation-sys 0.6.2", - "libc", -] +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" [[package]] name = "core-foundation" @@ -215,10 +212,14 @@ dependencies = [ ] [[package]] -name = "core-foundation-sys" -version = "0.6.2" +name = "core-foundation" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys 0.8.2", + "libc", +] [[package]] name = "core-foundation-sys" @@ -227,25 +228,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] -name = "core-graphics" -version = "0.17.3" +name = "core-foundation-sys" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" +checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" dependencies = [ "bitflags", - "core-foundation 0.6.4", + "core-foundation 0.7.0", "foreign-types", "libc", ] [[package]] name = "core-graphics" -version = "0.19.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd" +checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" dependencies = [ "bitflags", - "core-foundation 0.7.0", + "core-foundation 0.9.1", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation 0.9.1", "foreign-types", "libc", ] @@ -256,20 +276,20 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "core-foundation-sys 0.7.0", - "core-graphics 0.19.0", + "core-graphics 0.19.2", "libc", "objc", ] [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -278,58 +298,94 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", + "cfg-if 0.1.10", + "crossbeam-channel 0.4.4", + "crossbeam-deque 0.7.3", + "crossbeam-epoch 0.8.2", "crossbeam-queue", - "crossbeam-utils", + "crossbeam-utils 0.7.2", ] [[package]] name = "crossbeam-channel" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "crossbeam-utils", + "crossbeam-utils 0.7.2", "maybe-uninit", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.1", +] + [[package]] name = "crossbeam-deque" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", "maybe-uninit", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch 0.9.1", + "crossbeam-utils 0.8.1", +] + [[package]] name = "crossbeam-epoch" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 1.0.0", - "cfg-if", - "crossbeam-utils", + "autocfg", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", - "memoffset", + "memoffset 0.5.6", + "scopeguard", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +dependencies = [ + "cfg-if 1.0.0", + "const_fn", + "crossbeam-utils 0.8.1", + "lazy_static", + "memoffset 0.6.1", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ - "cfg-if", - "crossbeam-utils", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] @@ -338,16 +394,62 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0", - "cfg-if", + "autocfg", + "cfg-if 0.1.10", "lazy_static", ] [[package]] -name = "deflate" -version = "0.8.4" +name = "crossbeam-utils" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e5d2a2273fed52a7f947ee55b092c4057025d7a3e04e5ecdbd25d6c3fb1bd7" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" dependencies = [ "adler32", "byteorder", @@ -355,12 +457,12 @@ dependencies = [ [[package]] name = "derivative" -version = "2.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" +checksum = "eaed5874effa6cde088c644ddcdcb4ffd1511391c5be4fdd7a5ccd02c7e4a183" dependencies = [ - "proc-macro2 1.0.17", - "quote 1.0.6", + "proc-macro2", + "quote", "syn", ] @@ -381,15 +483,15 @@ dependencies = [ [[package]] name = "downcast-rs" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "either" -version = "1.5.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" @@ -434,12 +536,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -458,12 +554,12 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "gif" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471d90201b3b223f3451cd4ad53e34295f16a1df17b1edf3736d47761c3981af" +checksum = "02efba560f227847cb41463a7395c514d127d4f74fff12ef0137fff1b84b96c4" dependencies = [ "color_quant", - "lzw", + "weezl", ] [[package]] @@ -474,9 +570,9 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" [[package]] name = "hermit-abi" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] @@ -491,13 +587,20 @@ dependencies = [ ] [[package]] -name = "image" -version = "0.23.4" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f4167a8f21fa2bb3f17a652a760acd7572645281c98e3b612a26242c96ee" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "image" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce04077ead78e39ae8610ad26216aed811996b043d47beed5090db674f9e9b5" dependencies = [ "bytemuck", "byteorder", + "color_quant", "gif", "jpeg-decoder", "num-iter", @@ -508,20 +611,14 @@ dependencies = [ "tiff", ] -[[package]] -name = "inflate" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" -dependencies = [ - "adler32", -] - [[package]] name = "instant" -version = "0.1.4" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7777a24a1ce5de49fcdde84ec46efa487c3af49d5b6e6e0a50367cc5c1096182" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] [[package]] name = "iovec" @@ -540,9 +637,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jpeg-decoder" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b47b4c4e017b01abdc5bcc126d2d1002e5a75bbe3ce73f9f4f311a916363704" +checksum = "cc797adac5f083b8ff0ca6f6294a999393d76e197c36488e2ef732c4715f6fa3" dependencies = [ "byteorder", "rayon", @@ -566,58 +663,44 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libloading" -version = "0.6.2" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cadb8e769f070c45df05c78c7520eb4cd17061d4ab262e43cfc68b4d00ac71c" +checksum = "e9367bdfa836b7e3cf895867f7a570283444da90562980ec2263d6e1569b16bc" dependencies = [ - "winapi 0.3.8", -] - -[[package]] -name = "line_drawing" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" -dependencies = [ - "num-traits", + "cfg-if 1.0.0", + "winapi 0.3.9", ] [[package]] name = "lock_api" -version = "0.3.4" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" dependencies = [ "scopeguard", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] -[[package]] -name = "lzw" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" - [[package]] name = "malloc_buf" version = "0.0.6" @@ -635,39 +718,47 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] -name = "memmap" -version = "0.7.0" +name = "memmap2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a" dependencies = [ "libc", - "winapi 0.3.8", ] [[package]] name = "memoffset" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "autocfg 1.0.0", + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg", ] [[package]] name = "metal" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83c7dcc2038e12f68493fa3de44235df27b2497178e257185b4b5b5d028a1e4" +checksum = "e198a0ee42bdbe9ef2c09d0b9426f3b2b47d90d93a4a9b0395c4cea605e92dc0" dependencies = [ "bitflags", "block", - "cocoa 0.19.1", - "core-graphics 0.17.3", + "cocoa 0.20.2", + "core-graphics 0.19.2", "foreign-types", "log", "objc", @@ -675,20 +766,30 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" dependencies = [ "adler32", ] [[package]] -name = "mio" -version = "0.6.22" +name = "miniz_oxide" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ - "cfg-if", + "adler", + "autocfg", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", @@ -715,9 +816,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ "kernel32-sys", "net2", @@ -727,98 +828,133 @@ dependencies = [ [[package]] name = "ndk" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a356cafe20aee088789830bfea3a61336e84ded9e545e00d3869ce95dcb80c" +checksum = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" dependencies = [ "jni-sys", "ndk-sys", "num_enum", + "thiserror", ] [[package]] name = "ndk-glue" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1730ee2e3de41c3321160a6da815f008c4006d71b095880ea50e17cf52332b8" +checksum = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" dependencies = [ - "android_log-sys", "lazy_static", "libc", "log", "ndk", + "ndk-macro", "ndk-sys", ] [[package]] -name = "ndk-sys" -version = "0.1.0" +name = "ndk-macro" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2820aca934aba5ed91c79acc72b6a44048ceacc5d36c035ed4e051f12d887d" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" [[package]] name = "net2" -version = "0.2.34" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] name = "nix" -version = "0.14.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" dependencies = [ "bitflags", "cc", - "cfg-if", + "cfg-if 0.1.10", "libc", - "void", +] + +[[package]] +name = "nix" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", +] + +[[package]] +name = "nom" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88034cfd6b4a0d54dd14f4a507eceee36c0b70e5a02236c4e4df571102be17f0" +dependencies = [ + "memchr", + "version_check", ] [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.0", + "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.40" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" dependencies = [ - "autocfg 1.0.0", + "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-rational" -version = "0.2.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ - "autocfg 1.0.0", + "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.0", + "autocfg", ] [[package]] @@ -848,8 +984,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.17", - "quote 1.0.6", + "proc-macro2", + "quote", "syn", ] @@ -873,55 +1009,43 @@ dependencies = [ ] [[package]] -name = "openvr" +name = "once_cell" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" + +[[package]] +name = "owned_ttf_parser" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93a827c3232d7e9065068234b794ab61aed3381ba40e97d99fac85a469e23360" +checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" dependencies = [ - "lazy_static", - "openvr_sys", -] - -[[package]] -name = "openvr_sys" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46af40862e3c6be0c176d4b8cf1f7af0f8038cfb500e9cd57c82ad945a29b4b8" -dependencies = [ - "cmake", -] - -[[package]] -name = "ordered-float" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" -dependencies = [ - "num-traits", + "ttf-parser", ] [[package]] name = "parking_lot" -version = "0.10.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ + "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" dependencies = [ - "cfg-if", - "cloudabi", + "cfg-if 1.0.0", + "instant", "libc", "redox_syscall", "smallvec", - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -932,47 +1056,38 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pkg-config" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "png" -version = "0.16.3" +version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c68a431ed29933a4eb5709aca9800989758c97759345860fa5db3cfced0b65d" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" dependencies = [ "bitflags", "crc32fast", "deflate", - "inflate", + "miniz_oxide 0.3.7", ] [[package]] name = "proc-macro-crate" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ "toml", ] [[package]] name = "proc-macro2" -version = "0.4.30" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" -dependencies = [ - "unicode-xid 0.2.0", + "unicode-xid", ] [[package]] @@ -983,126 +1098,11 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "0.6.13" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" -dependencies = [ - "proc-macro2 1.0.17", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi 0.3.8", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi 0.3.8", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi 0.3.8", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", + "proc-macro2", ] [[package]] @@ -1116,48 +1116,40 @@ dependencies = [ [[package]] name = "rayon" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" dependencies = [ - "crossbeam-deque", + "autocfg", + "crossbeam-deque 0.8.0", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ - "crossbeam-deque", - "crossbeam-queue", - "crossbeam-utils", + "crossbeam-channel 0.5.0", + "crossbeam-deque 0.8.0", + "crossbeam-utils 0.8.1", "lazy_static", "num_cpus", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "regex" -version = "1.3.9" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", @@ -1167,28 +1159,18 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "rusttype" -version = "0.7.9" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" +checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" dependencies = [ - "rusttype 0.8.3", -] - -[[package]] -name = "rusttype" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0" -dependencies = [ - "approx", - "ordered-float", - "stb_truetype", + "ab_glyph_rasterizer", + "owned_ttf_parser", ] [[package]] @@ -1200,6 +1182,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + [[package]] name = "scoped_threadpool" version = "0.1.9" @@ -1214,9 +1202,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.110" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" [[package]] name = "shared_library" @@ -1236,118 +1224,139 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" +checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" [[package]] name = "smithay-client-toolkit" -version = "0.6.6" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "421c8dc7acf5cb205b88160f8b4cc2c5cfabe210e43b2f80f009f4c1ef910f1d" +checksum = "316e13a3eb853ce7bf72ad3530dc186cb2005c57c521ef5f4ada5ee4eed74de6" dependencies = [ "andrew", "bitflags", + "calloop", "dlib", "lazy_static", - "memmap", - "nix", + "log", + "memmap2", + "nix 0.18.0", "wayland-client", + "wayland-cursor", "wayland-protocols", ] [[package]] -name = "stb_truetype" -version = "0.3.1" +name = "strsim" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" -dependencies = [ - "byteorder", -] +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "syn" -version = "1.0.27" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" dependencies = [ - "proc-macro2 1.0.17", - "quote 1.0.6", - "unicode-xid 0.2.0", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "termcolor" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] [[package]] -name = "thread_local" -version = "1.0.1" +name = "thiserror" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" dependencies = [ "lazy_static", ] [[package]] name = "tiff" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002351e428db1eb1d8656d4ca61947c3519ac3191e1c804d4600cd32093b77ad" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" dependencies = [ - "byteorder", - "lzw", - "miniz_oxide", + "jpeg-decoder", + "miniz_oxide 0.4.3", + "weezl", ] [[package]] name = "toml" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "serde", ] [[package]] -name = "unicode-xid" -version = "0.1.0" +name = "ttf-parser" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "vk-sys" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24c107c0402856ad434d2dc0f3dbdc68c9e170e8bab0f27aa82a282d234d57c" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "712e7b00b858d5a65e4272e3dfd83f795a31467ba67425d853f32b966a09c907" [[package]] name = "vulkano" -version = "0.18.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eb8a191577df4f71d70c31e5b69c56be2f3e88a87cbd6ad6e40ae06b38dc542" +checksum = "8f566b50e4f42000f48027dad19b38c41068657193feb59aa0b399664f5bf80d" dependencies = [ "crossbeam", "fnv", "half", "lazy_static", + "parking_lot", "shared_library", "smallvec", "vk-sys", @@ -1355,13 +1364,14 @@ dependencies = [ [[package]] name = "vulkano-win" -version = "0.18.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7e4c74bbf33d0c6b9f7e98f47068c62dc65d6a0721c0cb4b05fe4776c9af80" +checksum = "5aa56544406650fb1472510fc75a28078316df9a27e4123504f080261e3c3406" dependencies = [ - "cocoa 0.20.1", + "cocoa 0.20.2", "metal", "objc", + "raw-window-handle", "vulkano", "winit", ] @@ -1373,22 +1383,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" dependencies = [ "same-file", - "winapi 0.3.8", + "winapi 0.3.9", "winapi-util", ] [[package]] name = "wayland-client" -version = "0.23.6" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" +checksum = "bdbdbe01d03b2267809f3ed99495b37395387fde789e0f2ebb78e8b43f75b6d7" dependencies = [ "bitflags", - "calloop", "downcast-rs", "libc", - "mio", - "nix", + "nix 0.18.0", + "scoped-tls", "wayland-commons", "wayland-scanner", "wayland-sys", @@ -1396,19 +1405,32 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.23.6" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" +checksum = "480450f76717edd64ad04a4426280d737fc3d10a236b982df7b1aee19f0e2d56" dependencies = [ - "nix", + "nix 0.18.0", + "once_cell", + "smallvec", "wayland-sys", ] [[package]] -name = "wayland-protocols" -version = "0.23.6" +name = "wayland-cursor" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" +checksum = "d6eb122c160223a7660feeaf949d0100281d1279acaaed3720eb3c9894496e5f" +dependencies = [ + "nix 0.18.0", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319a82b4d3054dd25acc32d9aee0f84fa95b63bc983fffe4703b6b8d47e01a30" dependencies = [ "bitflags", "wayland-client", @@ -1418,25 +1440,32 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.23.6" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d" +checksum = "7010ba5767b3fcd350decc59055390b4ebe6bd1b9279a9feb1f1888987f1133d" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", + "proc-macro2", + "quote", "xml-rs", ] [[package]] name = "wayland-sys" -version = "0.23.6" +version = "0.28.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" +checksum = "6793834e0c35d11fd96a97297abe03d37be627e1847da52e17d7e0e3b51cc099" dependencies = [ "dlib", "lazy_static", + "pkg-config", ] +[[package]] +name = "weezl" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2bb9fc8309084dd7cd651336673844c1d47f8ef6d2091ec160b27f5c4aa277" + [[package]] name = "winapi" version = "0.2.8" @@ -1445,9 +1474,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -1471,7 +1500,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.8", + "winapi 0.3.9", ] [[package]] @@ -1482,14 +1511,14 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winit" -version = "0.22.2" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e4ccbf7ddb6627828eace16cacde80fc6bf4dbb3469f88487262a02cf8e7862" +checksum = "da4eda6fce0eb84bd0a33e3c8794eb902e1033d0a1d5a31bc4f19b1b4bbff597" dependencies = [ "bitflags", - "cocoa 0.20.1", - "core-foundation 0.7.0", - "core-graphics 0.19.0", + "cocoa 0.24.0", + "core-foundation 0.9.1", + "core-graphics 0.22.2", "core-video-sys", "dispatch", "instant", @@ -1507,7 +1536,7 @@ dependencies = [ "raw-window-handle", "smithay-client-toolkit", "wayland-client", - "winapi 0.3.8", + "winapi 0.3.9", "x11-dl", ] @@ -1533,6 +1562,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xcursor" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08" +dependencies = [ + "nom", +] + [[package]] name = "xdg" version = "2.2.0" diff --git a/third_party/cargo/Cargo.toml b/third_party/cargo/Cargo.toml index 33725cc..202d684 100644 --- a/third_party/cargo/Cargo.toml +++ b/third_party/cargo/Cargo.toml @@ -10,11 +10,11 @@ path = "fake_lib.rs" env_logger = "0.6.1" image = "0.23.1" log = "0.4.6" -vulkano = "0.18.0" -vulkano-win = "0.18.0" -winit = "0.22.0" -cgmath = "0.17.0" -openvr = "0.6.0" +vulkano = "0.20.0" +vulkano-win = "0.20.0" +winit = "0.24.0" +cgmath = "0.18.0" +#openvr = "0.6.0" flatbuffers = "0.6.1" [workspace.metadata.raze] @@ -43,11 +43,23 @@ additional_flags = [ "--cfg=atomic_cas" ] -[workspace.metadata.raze.crates.libloading.'0.6.2'] +[workspace.metadata.raze.crates.libloading.'0.6.6'] additional_deps = ['//third_party/cargo/patches:libloading_global_static'] -[workspace.metadata.raze.crates.cgmath.'0.17.0'] +[workspace.metadata.raze.crates.cgmath.'0.18.0'] gen_buildrs = true -[workspace.metadata.raze.crates.image.'0.23.4'] +[workspace.metadata.raze.crates.image.'0.23.12'] +gen_buildrs = true + +[workspace.metadata.raze.crates.num-rational.'0.3.2'] +gen_buildrs = true + +[workspace.metadata.raze.crates.libc.'0.2.82'] +gen_buildrs = true + +[workspace.metadata.raze.crates.wayland-client.'0.28.3'] +gen_buildrs = true + +[workspace.metadata.raze.crates.wayland-protocols.'0.28.3'] gen_buildrs = true diff --git a/third_party/cargo/patches/BUILD.bazel b/third_party/cargo/patches/BUILD.bazel index 7ba482f..e9923fc 100644 --- a/third_party/cargo/patches/BUILD.bazel +++ b/third_party/cargo/patches/BUILD.bazel @@ -2,5 +2,5 @@ cc_library( name = "libloading_global_static", srcs = ["libloading/global_static.c"], copts = ["-fPIC"], - visibility = ["//third_party/cargo/vendor/libloading-0.6.2:__pkg__"], + visibility = ["//third_party/cargo/vendor/libloading-0.6.6:__pkg__"], ) diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/.cargo-checksum.json b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/.cargo-checksum.json new file mode 100644 index 0000000..0086d72 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"12997ba678cbef530fcd89e4e9b071bad7a63f2c21127a9895d12a71c4762f72","Cargo.toml":"74cdeb71983a9e460620aeba81a0ea6c98d6b656558d6b17bfff3e64c172a071","README.md":"59162e54bce67b4181f793866a73e4906b3cb4b45f3487f045aca2ce06611a80","src/geometry.rs":"8d970a944af7199ac6a42ace5d1ca661f7764d10a2af0eb09f7b356547f80cf8","src/lib.rs":"32f718b6be690d4d22fa60bf2d2f3b73f645e293a12f0e7c969c7ff2ac2f0a54","src/nostd_float.rs":"425e4f7a3c20213d561a376a09cb75a37ba3989b42e1700a3b15f642ccb99918","src/raster.rs":"49171451f8447d5200da96c5698cb4cd9e4d1556bb8d4cc76e998d48297d4f95","tests/issues.rs":"dff1f0f9992a49a71b3ac4e298033fe9687194a7948bdf29b110daa1ccc99790"},"package":"d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff"} \ No newline at end of file diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/BUILD.bazel b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/BUILD.bazel new file mode 100644 index 0000000..8bf4e34 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/BUILD.bazel @@ -0,0 +1,57 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Apache-2.0 from expression "Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "ab_glyph_rasterizer", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.1.4", + # buildifier: leave-alone + deps = [ + ], +) + +# Unsupported target "issues" with type "test" omitted diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/CHANGELOG.md b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/CHANGELOG.md new file mode 100644 index 0000000..f10ba11 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/CHANGELOG.md @@ -0,0 +1,16 @@ +# 0.1.4 +* Add `Rasterizer::reset`, `Rasterizer::clear` methods to allow allocation reuse. + +# 0.1.3 +* Fix index oob panic scenario. + +# 0.1.2 +* For `Point` implement `Sub`, `Add`, `SubAssign`, `AddAssign`, `PartialEq`, `PartialOrd`, `From<(x, y)>`, + `From<[x, y]>` for easier use downstream. +* Switch `Point` `Debug` implementation to output `point(1.2, 3.4)` smaller representation referring to the `point` fn. + +# 0.1.1 +* Add explicit compile error when building no_std without the "libm" feature. + +# 0.1 +* Implement zero dependency coverage rasterization for lines, quadratic & cubic beziers. diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/Cargo.toml b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/Cargo.toml new file mode 100644 index 0000000..9e74640 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "ab_glyph_rasterizer" +version = "0.1.4" +authors = ["Alex Butler "] +description = "Coverage rasterization for lines, quadratic & cubic beziers" +readme = "README.md" +keywords = ["text", "ttf", "otf", "font"] +license = "Apache-2.0" +repository = "https://github.com/alexheretic/ab-glyph" +[dependencies.libm] +version = "0.2.1" +optional = true + +[dev-dependencies] + +[features] +default = ["std"] +std = [] diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/README.md b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/README.md new file mode 100644 index 0000000..72337e6 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/README.md @@ -0,0 +1,51 @@ +ab_glyph_rasterizer +[![crates.io](https://img.shields.io/crates/v/ab_glyph_rasterizer.svg)](https://crates.io/crates/ab_glyph_rasterizer) +[![Documentation](https://docs.rs/ab_glyph_rasterizer/badge.svg)](https://docs.rs/ab_glyph_rasterizer) +=================== +Coverage rasterization for lines, quadratic & cubic beziers. +Useful for drawing .otf font glyphs. + +Inspired by [font-rs](https://github.com/raphlinus/font-rs) & +[stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h). + +## Example + +```rust +let mut rasterizer = ab_glyph_rasterizer::Rasterizer::new(106, 183); + +// draw a 300px 'ę' character +rasterizer.draw_cubic(point(103.0, 163.5), point(86.25, 169.25), point(77.0, 165.0), point(82.25, 151.5)); +rasterizer.draw_cubic(point(82.25, 151.5), point(86.75, 139.75), point(94.0, 130.75), point(102.0, 122.0)); +rasterizer.draw_line(point(102.0, 122.0), point(100.25, 111.25)); +rasterizer.draw_cubic(point(100.25, 111.25), point(89.0, 112.75), point(72.75, 114.25), point(58.5, 114.25)); +rasterizer.draw_cubic(point(58.5, 114.25), point(30.75, 114.25), point(18.5, 105.25), point(16.75, 72.25)); +rasterizer.draw_line(point(16.75, 72.25), point(77.0, 72.25)); +rasterizer.draw_cubic(point(77.0, 72.25), point(97.0, 72.25), point(105.25, 60.25), point(104.75, 38.5)); +rasterizer.draw_cubic(point(104.75, 38.5), point(104.5, 13.5), point(89.0, 0.75), point(54.25, 0.75)); +rasterizer.draw_cubic(point(54.25, 0.75), point(16.0, 0.75), point(0.0, 16.75), point(0.0, 64.0)); +rasterizer.draw_cubic(point(0.0, 64.0), point(0.0, 110.5), point(16.0, 128.0), point(56.5, 128.0)); +rasterizer.draw_cubic(point(56.5, 128.0), point(66.0, 128.0), point(79.5, 127.0), point(90.0, 125.0)); +rasterizer.draw_cubic(point(90.0, 125.0), point(78.75, 135.25), point(73.25, 144.5), point(70.75, 152.0)); +rasterizer.draw_cubic(point(70.75, 152.0), point(64.5, 169.0), point(75.5, 183.0), point(105.0, 170.5)); +rasterizer.draw_line(point(105.0, 170.5), point(103.0, 163.5)); +rasterizer.draw_cubic(point(55.0, 14.5), point(78.5, 14.5), point(88.5, 21.75), point(88.75, 38.75)); +rasterizer.draw_cubic(point(88.75, 38.75), point(89.0, 50.75), point(85.75, 59.75), point(73.5, 59.75)); +rasterizer.draw_line(point(73.5, 59.75), point(16.5, 59.75)); +rasterizer.draw_cubic(point(16.5, 59.75), point(17.25, 25.5), point(27.0, 14.5), point(55.0, 14.5)); +rasterizer.draw_line(point(55.0, 14.5), point(55.0, 14.5)); + +// iterate over the resultant pixel alphas, e.g. save pixel to a buffer +rasterizer.for_each_pixel(|index, alpha| { + // ... +}); +``` + +Rendering the resultant pixel alphas as 8-bit grey produces: + +![reference_otf_tailed_e](https://user-images.githubusercontent.com/2331607/78987793-ee95f480-7b26-11ea-91fb-e9f359d766f8.png) + +## no_std +no_std environments are supported using `alloc` & [`libm`](https://github.com/rust-lang/libm). +```toml +ab_glyph_rasterizer = { default-features = false, features = ["libm"] } +``` diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/geometry.rs b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/geometry.rs new file mode 100644 index 0000000..2f4bb74 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/geometry.rs @@ -0,0 +1,148 @@ +#[cfg(all(feature = "libm", not(feature = "std")))] +use crate::nostd_float::FloatExt; + +/// An (x, y) coordinate. +/// +/// # Example +/// ``` +/// use ab_glyph_rasterizer::{point, Point}; +/// let p: Point = point(0.1, 23.2); +/// ``` +#[derive(Clone, Copy, Default, PartialEq, PartialOrd)] +pub struct Point { + pub x: f32, + pub y: f32, +} + +impl core::fmt::Debug for Point { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "point({:?}, {:?})", self.x, self.y) + } +} + +impl Point { + #[inline] + pub(crate) fn distance_to(self, other: Point) -> f32 { + let d = other - self; + (d.x * d.x + d.y * d.y).sqrt() + } +} + +/// [`Point`](struct.Point.html) constructor. +/// +/// # Example +/// ``` +/// # use ab_glyph_rasterizer::{point, Point}; +/// let p = point(0.1, 23.2); +/// ``` +#[inline] +pub fn point(x: f32, y: f32) -> Point { + Point { x, y } +} + +/// Linear interpolation between points. +#[inline] +pub(crate) fn lerp(t: f32, p0: Point, p1: Point) -> Point { + point(p0.x + t * (p1.x - p0.x), p0.y + t * (p1.y - p0.y)) +} + +impl core::ops::Sub for Point { + type Output = Point; + /// Subtract rhs.x from x, rhs.y from y. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let p1 = point(1.0, 2.0) - point(2.0, 1.5); + /// + /// assert!((p1.x - -1.0).abs() <= core::f32::EPSILON); + /// assert!((p1.y - 0.5).abs() <= core::f32::EPSILON); + /// ``` + #[inline] + fn sub(self, rhs: Point) -> Point { + point(self.x - rhs.x, self.y - rhs.y) + } +} + +impl core::ops::Add for Point { + type Output = Point; + /// Add rhs.x to x, rhs.y to y. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let p1 = point(1.0, 2.0) + point(2.0, 1.5); + /// + /// assert!((p1.x - 3.0).abs() <= core::f32::EPSILON); + /// assert!((p1.y - 3.5).abs() <= core::f32::EPSILON); + /// ``` + #[inline] + fn add(self, rhs: Point) -> Point { + point(self.x + rhs.x, self.y + rhs.y) + } +} + +impl core::ops::AddAssign for Point { + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let mut p1 = point(1.0, 2.0); + /// p1 += point(2.0, 1.5); + /// + /// assert!((p1.x - 3.0).abs() <= core::f32::EPSILON); + /// assert!((p1.y - 3.5).abs() <= core::f32::EPSILON); + /// ``` + #[inline] + fn add_assign(&mut self, other: Self) { + self.x += other.x; + self.y += other.y; + } +} + +impl core::ops::SubAssign for Point { + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let mut p1 = point(1.0, 2.0); + /// p1 -= point(2.0, 1.5); + /// + /// assert!((p1.x - -1.0).abs() <= core::f32::EPSILON); + /// assert!((p1.y - 0.5).abs() <= core::f32::EPSILON); + /// ``` + #[inline] + fn sub_assign(&mut self, other: Self) { + self.x -= other.x; + self.y -= other.y; + } +} + +impl> From<(F, F)> for Point { + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let p: Point = (23_f32, 34.5_f32).into(); + /// let p2: Point = (5u8, 44u8).into(); + /// ``` + #[inline] + fn from((x, y): (F, F)) -> Self { + point(x.into(), y.into()) + } +} + +impl> From<[F; 2]> for Point { + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let p: Point = [23_f32, 34.5].into(); + /// let p2: Point = [5u8, 44].into(); + /// ``` + #[inline] + fn from([x, y]: [F; 2]) -> Self { + point(x.into(), y.into()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn distance_to() { + let distance = point(0.0, 0.0).distance_to(point(3.0, 4.0)); + assert!((distance - 5.0).abs() <= core::f32::EPSILON); + } +} diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/lib.rs b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/lib.rs new file mode 100644 index 0000000..51e5b14 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/lib.rs @@ -0,0 +1,36 @@ +//! Coverage rasterization for lines, quadratic & cubic beziers. +//! Useful for drawing .otf font glyphs. +//! +//! ``` +//! use ab_glyph_rasterizer::Rasterizer; +//! # let (width, height) = (1, 1); +//! let mut rasterizer = Rasterizer::new(width, height); +//! +//! // draw outlines +//! # let [l0, l1, q0, q1, q2, c0, c1, c2, c3] = [ab_glyph_rasterizer::point(0.0, 0.0); 9]; +//! rasterizer.draw_line(l0, l1); +//! rasterizer.draw_quad(q0, q1, q2); +//! rasterizer.draw_cubic(c0, c1, c2, c3); +//! +//! // iterate over the resultant pixel alphas, e.g. save pixel to a buffer +//! rasterizer.for_each_pixel(|index, alpha| { +//! // ... +//! }); +//! ``` + +#![cfg_attr(not(feature = "std"), no_std)] +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; + +#[cfg(all(feature = "libm", not(feature = "std")))] +mod nostd_float; + +#[cfg(not(any(feature = "libm", feature = "std")))] +compile_error!("You need to activate either the `std` or `libm` feature."); + +mod geometry; +mod raster; + +pub use geometry::{point, Point}; +pub use raster::Rasterizer; diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/nostd_float.rs b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/nostd_float.rs new file mode 100644 index 0000000..8da4739 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/nostd_float.rs @@ -0,0 +1,31 @@ +/// Basic required float operations. +pub(crate) trait FloatExt { + fn floor(self) -> Self; + fn ceil(self) -> Self; + fn sqrt(self) -> Self; + fn round(self) -> Self; + fn abs(self) -> Self; +} + +impl FloatExt for f32 { + #[inline] + fn floor(self) -> Self { + libm::floorf(self) + } + #[inline] + fn ceil(self) -> Self { + libm::ceilf(self) + } + #[inline] + fn sqrt(self) -> Self { + libm::sqrtf(self) + } + #[inline] + fn round(self) -> Self { + libm::roundf(self) + } + #[inline] + fn abs(self) -> Self { + libm::fabsf(self) + } +} diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/raster.rs b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/raster.rs new file mode 100644 index 0000000..a491d15 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/src/raster.rs @@ -0,0 +1,286 @@ +// Forked/repurposed from `font-rs` code: https://github.com/raphlinus/font-rs +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Modifications copyright (C) 2020 Alex Butler +// +// Cubic bezier drawing adapted from stb_truetype: https://github.com/nothings/stb +#[cfg(all(feature = "libm", not(feature = "std")))] +use crate::nostd_float::FloatExt; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +use crate::geometry::{lerp, Point}; + +/// Coverage rasterizer for lines, quadratic & cubic beziers. +pub struct Rasterizer { + width: usize, + height: usize, + a: Vec, +} + +impl Rasterizer { + /// Allocates a new rasterizer that can draw onto a `width` x `height` alpha grid. + /// + /// ``` + /// use ab_glyph_rasterizer::Rasterizer; + /// let mut rasterizer = Rasterizer::new(14, 38); + /// ``` + pub fn new(width: usize, height: usize) -> Self { + Self { + width, + height, + a: vec![0.0; width * height + 4], + } + } + + /// Resets the rasterizer to an empty `width` x `height` alpha grid. This method behaves as if + /// the Rasterizer were re-created, with the advantage of not allocating if the total number of + /// pixels of the grid does not increase. + /// + /// ``` + /// # use ab_glyph_rasterizer::Rasterizer; + /// # let mut rasterizer = Rasterizer::new(14, 38); + /// rasterizer.reset(12, 24); + /// assert_eq!(rasterizer.dimensions(), (12, 24)); + /// ``` + pub fn reset(&mut self, width: usize, height: usize) { + self.width = width; + self.height = height; + self.a.truncate(0); + self.a.resize(width * height + 4, 0.0); + } + + /// Clears the rasterizer. This method behaves as if the Rasterizer were re-created with the same + /// dimensions, but does not perform an allocation. + /// + /// ``` + /// # use ab_glyph_rasterizer::Rasterizer; + /// # let mut rasterizer = Rasterizer::new(14, 38); + /// rasterizer.clear(); + /// ``` + pub fn clear(&mut self) { + for px in &mut self.a { + *px = 0.0; + } + } + + /// Returns the dimensions the rasterizer was built to draw to. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let rasterizer = Rasterizer::new(9, 8); + /// assert_eq!((9, 8), rasterizer.dimensions()); + /// ``` + pub fn dimensions(&self) -> (usize, usize) { + (self.width, self.height) + } + + /// Adds a straight line from `p0` to `p1` to the outline. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let mut rasterizer = Rasterizer::new(9, 8); + /// rasterizer.draw_line(point(0.0, 0.48), point(1.22, 0.48)); + /// ``` + pub fn draw_line(&mut self, p0: Point, p1: Point) { + if (p0.y - p1.y).abs() <= core::f32::EPSILON { + return; + } + let (dir, p0, p1) = if p0.y < p1.y { + (1.0, p0, p1) + } else { + (-1.0, p1, p0) + }; + let dxdy = (p1.x - p0.x) / (p1.y - p0.y); + let mut x = p0.x; + let y0 = p0.y as usize; // note: implicit max of 0 because usize (TODO: really true?) + if p0.y < 0.0 { + x -= p0.y * dxdy; + } + for y in y0..self.height.min(p1.y.ceil() as usize) { + let linestart = y * self.width; + let dy = ((y + 1) as f32).min(p1.y) - (y as f32).max(p0.y); + let xnext = x + dxdy * dy; + let d = dy * dir; + let (x0, x1) = if x < xnext { (x, xnext) } else { (xnext, x) }; + let x0floor = x0.floor(); + let x0i = x0floor as i32; + let x1ceil = x1.ceil(); + let x1i = x1ceil as i32; + if x1i <= x0i + 1 { + let xmf = 0.5 * (x + xnext) - x0floor; + let linestart_x0i = linestart as isize + x0i as isize; + if linestart_x0i < 0 { + continue; // oob index + } + self.a[linestart_x0i as usize] += d - d * xmf; + self.a[linestart_x0i as usize + 1] += d * xmf; + } else { + let s = (x1 - x0).recip(); + let x0f = x0 - x0floor; + let a0 = 0.5 * s * (1.0 - x0f) * (1.0 - x0f); + let x1f = x1 - x1ceil + 1.0; + let am = 0.5 * s * x1f * x1f; + let linestart_x0i = linestart as isize + x0i as isize; + if linestart_x0i < 0 { + continue; // oob index + } + self.a[linestart_x0i as usize] += d * a0; + if x1i == x0i + 2 { + self.a[linestart_x0i as usize + 1] += d * (1.0 - a0 - am); + } else { + let a1 = s * (1.5 - x0f); + self.a[linestart_x0i as usize + 1] += d * (a1 - a0); + for xi in x0i + 2..x1i - 1 { + self.a[linestart + xi as usize] += d * s; + } + let a2 = a1 + (x1i - x0i - 3) as f32 * s; + self.a[linestart + (x1i - 1) as usize] += d * (1.0 - a2 - am); + } + self.a[linestart + x1i as usize] += d * am; + } + x = xnext; + } + } + + /// Adds a quadratic Bézier curve from `p0` to `p2` to the outline using `p1` as the control. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let mut rasterizer = Rasterizer::new(14, 38); + /// rasterizer.draw_quad(point(6.2, 34.5), point(7.2, 34.5), point(9.2, 34.0)); + /// ``` + pub fn draw_quad(&mut self, p0: Point, p1: Point, p2: Point) { + let devx = p0.x - 2.0 * p1.x + p2.x; + let devy = p0.y - 2.0 * p1.y + p2.y; + let devsq = devx * devx + devy * devy; + if devsq < 0.333 { + self.draw_line(p0, p2); + return; + } + let tol = 3.0; + let n = 1 + (tol * devsq).sqrt().sqrt().floor() as usize; + let mut p = p0; + let nrecip = (n as f32).recip(); + let mut t = 0.0; + for _i in 0..n - 1 { + t += nrecip; + let pn = lerp(t, lerp(t, p0, p1), lerp(t, p1, p2)); + self.draw_line(p, pn); + p = pn; + } + self.draw_line(p, p2); + } + + /// Adds a cubic Bézier curve from `p0` to `p3` to the outline using `p1` as the control + /// at the beginning of the curve and `p2` at the end of the curve. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let mut rasterizer = Rasterizer::new(12, 20); + /// rasterizer.draw_cubic( + /// point(10.3, 16.4), + /// point(8.6, 16.9), + /// point(7.7, 16.5), + /// point(8.2, 15.2), + /// ); + /// ``` + pub fn draw_cubic(&mut self, p0: Point, p1: Point, p2: Point, p3: Point) { + self.tesselate_cubic(p0, p1, p2, p3, 0); + } + + // stb_truetype style cubic approximation by lines. + fn tesselate_cubic(&mut self, p0: Point, p1: Point, p2: Point, p3: Point, n: u8) { + // ...I'm not sure either ¯\_(ツ)_/¯ + const OBJSPACE_FLATNESS: f32 = 0.35; + const OBJSPACE_FLATNESS_SQUARED: f32 = OBJSPACE_FLATNESS * OBJSPACE_FLATNESS; + const MAX_RECURSION_DEPTH: u8 = 16; + + let longlen = p0.distance_to(p1) + p1.distance_to(p2) + p2.distance_to(p3); + let shortlen = p0.distance_to(p3); + let flatness_squared = longlen * longlen - shortlen * shortlen; + + if n < MAX_RECURSION_DEPTH && flatness_squared > OBJSPACE_FLATNESS_SQUARED { + let p01 = lerp(0.5, p0, p1); + let p12 = lerp(0.5, p1, p2); + let p23 = lerp(0.5, p2, p3); + + let pa = lerp(0.5, p01, p12); + let pb = lerp(0.5, p12, p23); + + let mp = lerp(0.5, pa, pb); + + self.tesselate_cubic(p0, p01, pa, mp, n + 1); + self.tesselate_cubic(mp, pb, p23, p3, n + 1); + } else { + self.draw_line(p0, p3); + } + } + + /// Run a callback for each pixel index & alpha, with indices in `0..width * height`. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let (width, height) = (1, 1); + /// # let mut rasterizer = Rasterizer::new(width, height); + /// let mut pixels = vec![0u8; width * height]; + /// rasterizer.for_each_pixel(|index, alpha| { + /// pixels[index] = (alpha * 255.0).round() as u8; + /// }); + /// ``` + pub fn for_each_pixel(&self, mut px_fn: O) { + let mut acc = 0.0; + self.a[..self.width * self.height] + .iter() + .enumerate() + .for_each(|(idx, c)| { + acc += c; + px_fn(idx, acc.abs().min(1.0)); + }); + } + + /// Run a callback for each pixel x position, y position & alpha. + /// + /// Convenience wrapper for `for_each_pixel`. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let (width, height) = (1, 1); + /// # let mut rasterizer = Rasterizer::new(width, height); + /// # struct Img; + /// # impl Img { fn set_pixel(&self, x: u32, y: u32, a: u8) {} } + /// # let image = Img; + /// rasterizer.for_each_pixel_2d(|x, y, alpha| { + /// image.set_pixel(x, y, (alpha * 255.0).round() as u8); + /// }); + /// ``` + pub fn for_each_pixel_2d(&self, mut px_fn: O) { + let width32 = self.width as u32; + self.for_each_pixel(|idx, alpha| px_fn(idx as u32 % width32, idx as u32 / width32, alpha)); + } +} + +/// ``` +/// let rasterizer = ab_glyph_rasterizer::Rasterizer::new(3, 4); +/// assert_eq!(&format!("{:?}", rasterizer), "Rasterizer { width: 3, height: 4 }"); +/// ``` +impl core::fmt::Debug for Rasterizer { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Rasterizer") + .field("width", &self.width) + .field("height", &self.height) + .finish() + } +} diff --git a/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/tests/issues.rs b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/tests/issues.rs new file mode 100644 index 0000000..675ff94 --- /dev/null +++ b/third_party/cargo/vendor/ab_glyph_rasterizer-0.1.4/tests/issues.rs @@ -0,0 +1,10 @@ +use ab_glyph_rasterizer::*; + +/// Index oob panic rasterizing "Gauntl" using Bitter-Regular.otf +#[test] +fn rusttype_156_index_panic() { + let mut r = Rasterizer::new(6, 16); + r.draw_line(point(5.54, 14.299999), point(3.7399998, 13.799999)); + r.draw_line(point(3.7399998, 13.799999), point(3.7399998, 0.0)); + r.draw_line(point(3.7399998, 0.0), point(0.0, 0.10000038)); +} diff --git a/third_party/cargo/vendor/adler-0.2.3/.cargo-checksum.json b/third_party/cargo/vendor/adler-0.2.3/.cargo-checksum.json new file mode 100644 index 0000000..d06d0a5 --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"042ed3158af7000c88a6617d775f11456bd30f6c7c8b5b586978faa1e11b1e24","Cargo.toml":"107d13689eecfa82a8b5ae35bf835b9d2775337226630e4bdb35f22d0dd52e18","LICENSE-0BSD":"861399f8c21c042b110517e76dc6b63a2b334276c8cf17412fc3c8908ca8dc17","LICENSE-APACHE":"8ada45cd9f843acf64e4722ae262c622a2b3b3007c7310ef36ac1061a30f6adb","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"fa83fd5ee10b61827de382e496bf66296a526e3d2c3b2aa5ad672aa15e8d2d7f","RELEASE_PROCESS.md":"a86cd10fc70f167f8d00e9e4ce0c6b4ebdfa1865058390dffd1e0ad4d3e68d9d","benches/bench.rs":"c07ce370e3680c602e415f8d1ec4e543ea2163ab22a09b6b82d93e8a30adca82","src/algo.rs":"b664b131f724a809591394a10b9023f40ab5963e32a83fa3163c2668e59c8b66","src/lib.rs":"67f3ca5b6333e22745b178b70f472514162cea2890344724f0f66995fcf19806"},"package":"ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"} \ No newline at end of file diff --git a/third_party/cargo/vendor/adler-0.2.3/BUILD.bazel b/third_party/cargo/vendor/adler-0.2.3/BUILD.bazel new file mode 100644 index 0000000..ed795aa --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/BUILD.bazel @@ -0,0 +1,55 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "0BSD OR (MIT OR Apache-2.0)" +]) + +# Generated Targets + +# Unsupported target "bench" with type "bench" omitted + +rust_library( + name = "adler", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.2.3", + # buildifier: leave-alone + deps = [ + ], +) diff --git a/third_party/cargo/vendor/adler-0.2.3/CHANGELOG.md b/third_party/cargo/vendor/adler-0.2.3/CHANGELOG.md new file mode 100644 index 0000000..f055938 --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog + +## Unreleased + +No changes. + +## [0.2.3 - 2020-07-11](https://github.com/jonas-schievink/adler/releases/tag/v0.2.3) + +- Process 4 Bytes at a time, improving performance by up to 50% ([#2]). + +## [0.2.2 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.2) + +- Bump MSRV to 1.31.0. + +## [0.2.1 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.1) + +- Add a few `#[inline]` annotations to small functions. +- Fix CI badge. +- Allow integration into libstd. + +## [0.2.0 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.0) + +- Support `#![no_std]` when using `default-features = false`. +- Improve performance by around 7x. +- Support Rust 1.8.0. +- Improve API naming. + +## [0.1.0 - 2020-06-26](https://github.com/jonas-schievink/adler/releases/tag/v0.1.0) + +Initial release. + + +[#2]: https://github.com/jonas-schievink/adler/pull/2 diff --git a/third_party/cargo/vendor/adler-0.2.3/Cargo.toml b/third_party/cargo/vendor/adler-0.2.3/Cargo.toml new file mode 100644 index 0000000..dd2366c --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/Cargo.toml @@ -0,0 +1,69 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "adler" +version = "0.2.3" +authors = ["Jonas Schievink "] +description = "A simple clean-room implementation of the Adler-32 checksum" +documentation = "https://docs.rs/adler/" +readme = "README.md" +keywords = ["checksum", "integrity", "hash", "adler32"] +categories = ["algorithms"] +license = "0BSD OR MIT OR Apache-2.0" +repository = "https://github.com/jonas-schievink/adler.git" +[package.metadata.docs.rs] +rustdoc-args = ["--cfg docsrs"] + +[package.metadata.release] +no-dev-version = true +pre-release-commit-message = "Release {{version}}" +tag-message = "{{version}}" + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +replace = "## Unreleased\n\nNo changes.\n\n## [{{version}} - {{date}}](https://github.com/jonas-schievink/adler/releases/tag/v{{version}})\n" +search = "## Unreleased\n" + +[[package.metadata.release.pre-release-replacements]] +file = "README.md" +replace = "adler = \"{{version}}\"" +search = "adler = \"[a-z0-9\\\\.-]+\"" + +[[package.metadata.release.pre-release-replacements]] +file = "src/lib.rs" +replace = "https://docs.rs/adler/{{version}}" +search = "https://docs.rs/adler/[a-z0-9\\.-]+" + +[[bench]] +name = "bench" +harness = false +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" +[dev-dependencies.criterion] +version = "0.3.2" + +[features] +default = ["std"] +rustc-dep-of-std = ["core", "compiler_builtins"] +std = [] +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "jonas-schievink/adler" diff --git a/third_party/cargo/vendor/adler-0.2.3/LICENSE-0BSD b/third_party/cargo/vendor/adler-0.2.3/LICENSE-0BSD new file mode 100644 index 0000000..89336aa --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/LICENSE-0BSD @@ -0,0 +1,12 @@ +Copyright (C) Jonas Schievink + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/third_party/cargo/vendor/adler-0.2.3/LICENSE-APACHE b/third_party/cargo/vendor/adler-0.2.3/LICENSE-APACHE new file mode 100644 index 0000000..c98d27d --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/LICENSE-2.0 + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/cargo/vendor/hermit-abi-0.1.13/LICENSE-MIT b/third_party/cargo/vendor/adler-0.2.3/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/hermit-abi-0.1.13/LICENSE-MIT rename to third_party/cargo/vendor/adler-0.2.3/LICENSE-MIT diff --git a/third_party/cargo/vendor/adler-0.2.3/README.md b/third_party/cargo/vendor/adler-0.2.3/README.md new file mode 100644 index 0000000..0254db7 --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/README.md @@ -0,0 +1,38 @@ +# Adler-32 checksums for Rust + +[![crates.io](https://img.shields.io/crates/v/adler.svg)](https://crates.io/crates/adler) +[![docs.rs](https://docs.rs/adler/badge.svg)](https://docs.rs/adler/) +![CI](https://github.com/jonas-schievink/adler/workflows/CI/badge.svg) + +This crate provides a simple implementation of the Adler-32 checksum, used in +zlib, rsync, and other software. + +Please refer to the [changelog](CHANGELOG.md) to see what changed in the last +releases. + +## Features + +- Permissively licensed (0BSD) clean-room implementation. +- Zero dependencies. +- Decent performance (3-4 GB/s). +- Supports `#![no_std]` (with `default-features = false`). + +## Usage + +Add an entry to your `Cargo.toml`: + +```toml +[dependencies] +adler = "0.2.3" +``` + +Check the [API Documentation](https://docs.rs/adler/) for how to use the +crate's functionality. + +## Rust version support + +Currently, this crate supports all Rust versions starting at Rust 1.31.0. + +Bumping the Minimum Supported Rust Version (MSRV) is *not* considered a breaking +change, but will not be done without good reasons. The latest 3 stable Rust +versions will always be supported no matter what. diff --git a/third_party/cargo/vendor/adler-0.2.3/RELEASE_PROCESS.md b/third_party/cargo/vendor/adler-0.2.3/RELEASE_PROCESS.md new file mode 100644 index 0000000..71a3673 --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/RELEASE_PROCESS.md @@ -0,0 +1,13 @@ +# What to do to publish a new release + +1. Ensure all notable changes are in the changelog under "Unreleased". + +2. Execute `cargo release ` to bump version(s), tag and publish + everything. External subcommand, must be installed with `cargo install + cargo-release`. + + `` can be one of `major|minor|patch`. If this is the first release + (`0.1.0`), use `minor`, since the version starts out as `0.0.0`. + +3. Go to the GitHub releases, edit the just-pushed tag. Copy the release notes + from the changelog. diff --git a/third_party/cargo/vendor/adler-0.2.3/benches/bench.rs b/third_party/cargo/vendor/adler-0.2.3/benches/bench.rs new file mode 100644 index 0000000..0969f59 --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/benches/bench.rs @@ -0,0 +1,109 @@ +extern crate adler; +extern crate criterion; + +use adler::{adler32_slice, Adler32}; +use criterion::{criterion_group, criterion_main, Criterion, Throughput}; + +fn simple(c: &mut Criterion) { + { + const SIZE: usize = 100; + + let mut group = c.benchmark_group("simple-100b"); + group.throughput(Throughput::Bytes(SIZE as u64)); + group.bench_function("zeroes-100", |bencher| { + bencher.iter(|| { + adler32_slice(&[0; SIZE]); + }); + }); + group.bench_function("ones-100", |bencher| { + bencher.iter(|| { + adler32_slice(&[0xff; SIZE]); + }); + }); + } + + { + const SIZE: usize = 1024; + + let mut group = c.benchmark_group("simple-1k"); + group.throughput(Throughput::Bytes(SIZE as u64)); + + group.bench_function("zeroes-1k", |bencher| { + bencher.iter(|| { + adler32_slice(&[0; SIZE]); + }); + }); + + group.bench_function("ones-1k", |bencher| { + bencher.iter(|| { + adler32_slice(&[0xff; SIZE]); + }); + }); + } + + { + const SIZE: usize = 1024 * 1024; + + let mut group = c.benchmark_group("simple-1m"); + group.throughput(Throughput::Bytes(SIZE as u64)); + group.bench_function("zeroes-1m", |bencher| { + bencher.iter(|| { + adler32_slice(&[0; SIZE]); + }); + }); + + group.bench_function("ones-1m", |bencher| { + bencher.iter(|| { + adler32_slice(&[0xff; SIZE]); + }); + }); + } +} + +fn chunked(c: &mut Criterion) { + const SIZE: usize = 16 * 1024 * 1024; + + let data = vec![0xAB; SIZE]; + + let mut group = c.benchmark_group("chunked-16m"); + group.throughput(Throughput::Bytes(SIZE as u64)); + group.bench_function("5552", |bencher| { + bencher.iter(|| { + let mut h = Adler32::new(); + for chunk in data.chunks(5552) { + h.write_slice(chunk); + } + h.checksum() + }); + }); + group.bench_function("8k", |bencher| { + bencher.iter(|| { + let mut h = Adler32::new(); + for chunk in data.chunks(8 * 1024) { + h.write_slice(chunk); + } + h.checksum() + }); + }); + group.bench_function("64k", |bencher| { + bencher.iter(|| { + let mut h = Adler32::new(); + for chunk in data.chunks(64 * 1024) { + h.write_slice(chunk); + } + h.checksum() + }); + }); + group.bench_function("1m", |bencher| { + bencher.iter(|| { + let mut h = Adler32::new(); + for chunk in data.chunks(1024 * 1024) { + h.write_slice(chunk); + } + h.checksum() + }); + }); +} + +criterion_group!(benches, simple, chunked); +criterion_main!(benches); diff --git a/third_party/cargo/vendor/adler-0.2.3/src/algo.rs b/third_party/cargo/vendor/adler-0.2.3/src/algo.rs new file mode 100644 index 0000000..650cffa --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/src/algo.rs @@ -0,0 +1,146 @@ +use crate::Adler32; +use std::ops::{AddAssign, MulAssign, RemAssign}; + +impl Adler32 { + pub(crate) fn compute(&mut self, bytes: &[u8]) { + // The basic algorithm is, for every byte: + // a = (a + byte) % MOD + // b = (b + a) % MOD + // where MOD = 65521. + // + // For efficiency, we can defer the `% MOD` operations as long as neither a nor b overflows: + // - Between calls to `write`, we ensure that a and b are always in range 0..MOD. + // - We use 32-bit arithmetic in this function. + // - Therefore, a and b must not increase by more than 2^32-MOD without performing a `% MOD` + // operation. + // + // According to Wikipedia, b is calculated as follows for non-incremental checksumming: + // b = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n*1 (mod 65521) + // Where n is the number of bytes and Di is the i-th Byte. We need to change this to account + // for the previous values of a and b, as well as treat every input Byte as being 255: + // b_inc = n×255 + (n-1)×255 + ... + 255 + n*65520 + // Or in other words: + // b_inc = n*65520 + n(n+1)/2*255 + // The max chunk size is thus the largest value of n so that b_inc <= 2^32-65521. + // 2^32-65521 = n*65520 + n(n+1)/2*255 + // Plugging this into an equation solver since I can't math gives n = 5552.18..., so 5552. + // + // On top of the optimization outlined above, the algorithm can also be parallelized with a + // bit more work: + // + // Note that b is a linear combination of a vector of input bytes (D1, ..., Dn). + // + // If we fix some value k Self { + U32X4([ + u32::from(bytes[0]), + u32::from(bytes[1]), + u32::from(bytes[2]), + u32::from(bytes[3]), + ]) + } +} + +impl AddAssign for U32X4 { + fn add_assign(&mut self, other: Self) { + for (s, o) in self.0.iter_mut().zip(other.0.iter()) { + *s += o; + } + } +} + +impl RemAssign for U32X4 { + fn rem_assign(&mut self, quotient: u32) { + for s in self.0.iter_mut() { + *s %= quotient; + } + } +} + +impl MulAssign for U32X4 { + fn mul_assign(&mut self, rhs: u32) { + for s in self.0.iter_mut() { + *s *= rhs; + } + } +} diff --git a/third_party/cargo/vendor/adler-0.2.3/src/lib.rs b/third_party/cargo/vendor/adler-0.2.3/src/lib.rs new file mode 100644 index 0000000..ac29ea2 --- /dev/null +++ b/third_party/cargo/vendor/adler-0.2.3/src/lib.rs @@ -0,0 +1,215 @@ +//! Adler-32 checksum implementation. +//! +//! This implementation features: +//! +//! - Permissively licensed (0BSD) clean-room implementation. +//! - Zero dependencies. +//! - Decent performance (3-4 GB/s). +//! - `#![no_std]` support (with `default-features = false`). + +#![doc(html_root_url = "https://docs.rs/adler/0.2.3")] +// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default +#![doc(test(attr(deny(unused_imports, unused_must_use))))] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_debug_implementations)] +#![forbid(unsafe_code)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate core as std; + +mod algo; + +use std::hash::Hasher; + +#[cfg(feature = "std")] +use std::io::{self, BufRead}; + +/// Adler-32 checksum calculator. +/// +/// An instance of this type is equivalent to an Adler-32 checksum: It can be created in the default +/// state via [`new`] (or the provided `Default` impl), or from a precalculated checksum via +/// [`from_checksum`], and the currently stored checksum can be fetched via [`checksum`]. +/// +/// This type also implements `Hasher`, which makes it easy to calculate Adler-32 checksums of any +/// type that implements or derives `Hash`. This also allows using Adler-32 in a `HashMap`, although +/// that is not recommended (while every checksum is a hash, they are not necessarily good at being +/// one). +/// +/// [`new`]: #method.new +/// [`from_checksum`]: #method.from_checksum +/// [`checksum`]: #method.checksum +#[derive(Debug, Copy, Clone)] +pub struct Adler32 { + a: u16, + b: u16, +} + +impl Adler32 { + /// Creates a new Adler-32 instance with default state. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Creates an `Adler32` instance from a precomputed Adler-32 checksum. + /// + /// This allows resuming checksum calculation without having to keep the `Adler32` instance + /// around. + /// + /// # Example + /// + /// ``` + /// # use adler::Adler32; + /// let parts = [ + /// "rust", + /// "acean", + /// ]; + /// let whole = adler::adler32_slice(b"rustacean"); + /// + /// let mut sum = Adler32::new(); + /// sum.write_slice(parts[0].as_bytes()); + /// let partial = sum.checksum(); + /// + /// // ...later + /// + /// let mut sum = Adler32::from_checksum(partial); + /// sum.write_slice(parts[1].as_bytes()); + /// assert_eq!(sum.checksum(), whole); + /// ``` + #[inline] + pub fn from_checksum(sum: u32) -> Self { + Adler32 { + a: sum as u16, + b: (sum >> 16) as u16, + } + } + + /// Returns the calculated checksum at this point in time. + #[inline] + pub fn checksum(&self) -> u32 { + (u32::from(self.b) << 16) | u32::from(self.a) + } + + /// Adds `bytes` to the checksum calculation. + /// + /// If efficiency matters, this should be called with Byte slices that contain at least a few + /// thousand Bytes. + pub fn write_slice(&mut self, bytes: &[u8]) { + self.compute(bytes); + } +} + +impl Default for Adler32 { + #[inline] + fn default() -> Self { + Adler32 { a: 1, b: 0 } + } +} + +impl Hasher for Adler32 { + #[inline] + fn finish(&self) -> u64 { + u64::from(self.checksum()) + } + + fn write(&mut self, bytes: &[u8]) { + self.write_slice(bytes); + } +} + +/// Calculates the Adler-32 checksum of a byte slice. +pub fn adler32_slice(data: &[u8]) -> u32 { + let mut h = Adler32::new(); + h.write_slice(data); + h.checksum() +} + +/// Calculates the Adler-32 checksum of a `BufRead`'s contents. +/// +/// The passed `BufRead` implementor will be read until it reaches EOF. +/// +/// If you only have a `Read` implementor, wrap it in `std::io::BufReader`. +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +pub fn adler32_reader(reader: &mut R) -> io::Result { + let mut h = Adler32::new(); + loop { + let len = { + let buf = reader.fill_buf()?; + if buf.is_empty() { + return Ok(h.checksum()); + } + + h.write_slice(buf); + buf.len() + }; + reader.consume(len); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::BufReader; + + #[test] + fn zeroes() { + assert_eq!(adler32_slice(&[]), 1); + assert_eq!(adler32_slice(&[0]), 1 | 1 << 16); + assert_eq!(adler32_slice(&[0, 0]), 1 | 2 << 16); + assert_eq!(adler32_slice(&[0; 100]), 0x00640001); + assert_eq!(adler32_slice(&[0; 1024]), 0x04000001); + assert_eq!(adler32_slice(&[0; 1024 * 1024]), 0x00f00001); + } + + #[test] + fn ones() { + assert_eq!(adler32_slice(&[0xff; 1024]), 0x79a6fc2e); + assert_eq!(adler32_slice(&[0xff; 1024 * 1024]), 0x8e88ef11); + } + + #[test] + fn mixed() { + assert_eq!(adler32_slice(&[1]), 2 | 2 << 16); + assert_eq!(adler32_slice(&[40]), 41 | 41 << 16); + + assert_eq!(adler32_slice(&[0xA5; 1024 * 1024]), 0xd5009ab1); + } + + /// Example calculation from https://en.wikipedia.org/wiki/Adler-32. + #[test] + fn wiki() { + assert_eq!(adler32_slice(b"Wikipedia"), 0x11E60398); + } + + #[test] + fn resume() { + let mut adler = Adler32::new(); + adler.write_slice(&[0xff; 1024]); + let partial = adler.checksum(); + assert_eq!(partial, 0x79a6fc2e); // from above + adler.write_slice(&[0xff; 1024 * 1024 - 1024]); + assert_eq!(adler.checksum(), 0x8e88ef11); // from above + + // Make sure that we can resume computing from the partial checksum via `from_checksum`. + let mut adler = Adler32::from_checksum(partial); + adler.write_slice(&[0xff; 1024 * 1024 - 1024]); + assert_eq!(adler.checksum(), 0x8e88ef11); // from above + } + + #[test] + fn bufread() { + fn test(data: &[u8], checksum: u32) { + // `BufReader` uses an 8 KB buffer, so this will test buffer refilling. + let mut buf = BufReader::new(data); + let real_sum = adler32_reader(&mut buf).unwrap(); + assert_eq!(checksum, real_sum); + } + + test(&[], 1); + test(&[0; 1024], 0x04000001); + test(&[0; 1024 * 1024], 0x00f00001); + test(&[0xA5; 1024 * 1024], 0xd5009ab1); + } +} diff --git a/third_party/cargo/vendor/adler32-1.0.4/.cargo-checksum.json b/third_party/cargo/vendor/adler32-1.0.4/.cargo-checksum.json deleted file mode 100644 index 2a14a2c..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"3dfd0367a0af86dd57c4faf9f8a5b1ce8179c38e28d470d3c46ce2d2b45ef20f","LICENSE":"9efeecf73f68ed91830f71c69a53de1328d1f8c6968a68ca6e6b2d6f3a92a088","README.md":"77c9e2080e5ae700403343c27fe08bb616f1df92a8b42b0e7808a7b7d32eb7a2","appveyor.yml":"4873092bae0713890497e5ceae761af359d680e6cce5ce003bf38bc5c45cde44","src/lib.rs":"596ac0c2bbdfa759fb79eb7b7d9e18d6c51be0849f22204a85c4906fe2ae8bde"},"package":"5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"} \ No newline at end of file diff --git a/third_party/cargo/vendor/adler32-1.0.4/BUILD.bazel b/third_party/cargo/vendor/adler32-1.0.4/BUILD.bazel deleted file mode 100644 index e1f5e34..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/BUILD.bazel +++ /dev/null @@ -1,53 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # Zlib from expression "Zlib" -]) - -# Generated Targets - -rust_library( - name = "adler32", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.0.4", - # buildifier: leave-alone - deps = [ - ], -) diff --git a/third_party/cargo/vendor/adler32-1.0.4/Cargo.toml b/third_party/cargo/vendor/adler32-1.0.4/Cargo.toml deleted file mode 100644 index 39b77ce..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "adler32" -version = "1.0.4" -authors = ["Remi Rampin "] -description = "Minimal Adler32 implementation for Rust." -documentation = "https://remram44.github.io/adler32-rs/index.html" -readme = "README.md" -keywords = ["adler32", "hash", "rolling"] -license = "Zlib" -repository = "https://github.com/remram44/adler32-rs" -[dev-dependencies.rand] -version = "0.4" diff --git a/third_party/cargo/vendor/adler32-1.0.4/LICENSE b/third_party/cargo/vendor/adler32-1.0.4/LICENSE deleted file mode 100644 index 218a84b..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/LICENSE +++ /dev/null @@ -1,43 +0,0 @@ -Copyright notice for the Rust port: - - (C) 2016 Remi Rampin - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -Copyright notice for the original C code from the zlib project: - - (C) 1995-2017 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu diff --git a/third_party/cargo/vendor/adler32-1.0.4/README.md b/third_party/cargo/vendor/adler32-1.0.4/README.md deleted file mode 100644 index 3f96e74..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/README.md +++ /dev/null @@ -1,13 +0,0 @@ -[![Build Status](https://travis-ci.org/remram44/adler32-rs.svg?branch=master)](https://travis-ci.org/remram44/adler32-rs/builds) -[![Win Build](https://ci.appveyor.com/api/projects/status/ekyg20rd6rwrus64/branch/master?svg=true)](https://ci.appveyor.com/project/remram44/adler32-rs) -[![Crates.io](https://img.shields.io/crates/v/adler32.svg)](https://crates.io/crates/adler32) -[![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/remram44) - -What is this? -============= - -It is an implementation of the [Adler32 rolling hash algorithm](https://en.wikipedia.org/wiki/Adler-32) in the [Rust programming language](https://www.rust-lang.org/). - -It is adapted from Jean-Loup Gailly's and Mark Adler's [original implementation in zlib](https://github.com/madler/zlib/blob/2fa463bacfff79181df1a5270fb67cc679a53e71/adler32.c). A copy of the zlib copyright and license can be found in LICENSE-ZLIB. - -[Generated documentation](https://remram44.github.io/adler32-rs/index.html) diff --git a/third_party/cargo/vendor/adler32-1.0.4/appveyor.yml b/third_party/cargo/vendor/adler32-1.0.4/appveyor.yml deleted file mode 100644 index 03f815a..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/appveyor.yml +++ /dev/null @@ -1,12 +0,0 @@ -install: - - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe' - - rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" - - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin - - rustc -V - - cargo -V - -build: false - -test_script: - - cargo build --verbose - - cargo test --verbose diff --git a/third_party/cargo/vendor/adler32-1.0.4/src/lib.rs b/third_party/cargo/vendor/adler32-1.0.4/src/lib.rs deleted file mode 100644 index a894857..0000000 --- a/third_party/cargo/vendor/adler32-1.0.4/src/lib.rs +++ /dev/null @@ -1,307 +0,0 @@ -//! A minimal implementation of Adler32 for Rust. -//! -//! This provides the simple method adler32(), that exhausts a Read and -//! computes the Adler32 hash, as well as the RollingAdler32 struct, that can -//! build a hash byte-by-byte, allowing to 'forget' past bytes in a rolling -//! fashion. -//! -//! The adler32 code has been translated (as accurately as I could manage) from -//! the zlib implementation. - -#[cfg(test)] -extern crate rand; - -use std::io; - -// adler32 algorithm and implementation taken from zlib; http://www.zlib.net/ -// It was translated into Rust as accurately as I could manage -// The (slow) reference was taken from Wikipedia; https://en.wikipedia.org/ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.8, April 28th, 2013 - - Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - -*/ - -// largest prime smaller than 65536 -const BASE: u32 = 65521; - -// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 -const NMAX: usize = 5552; - -#[inline(always)] -fn do1(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { - *adler += u32::from(buf[0]); - *sum2 += *adler; -} - -#[inline(always)] -fn do2(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { - do1(adler, sum2, &buf[0..1]); - do1(adler, sum2, &buf[1..2]); -} - -#[inline(always)] -fn do4(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { - do2(adler, sum2, &buf[0..2]); - do2(adler, sum2, &buf[2..4]); -} - -#[inline(always)] -fn do8(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { - do4(adler, sum2, &buf[0..4]); - do4(adler, sum2, &buf[4..8]); -} - -#[inline(always)] -fn do16(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { - do8(adler, sum2, &buf[0..8]); - do8(adler, sum2, &buf[8..16]); -} - -/// A rolling version of the Adler32 hash, which can 'forget' past bytes. -/// -/// Calling remove() will update the hash to the value it would have if that -/// past byte had never been fed to the algorithm. This allows you to get the -/// hash of a rolling window very efficiently. -pub struct RollingAdler32 { - a: u32, - b: u32, -} - -impl Default for RollingAdler32 { - fn default() -> RollingAdler32 { - RollingAdler32::new() - } -} - -impl RollingAdler32 { - /// Creates an empty Adler32 context (with hash 1). - pub fn new() -> RollingAdler32 { - Self::from_value(1) - } - - /// Creates an Adler32 context with the given initial value. - pub fn from_value(adler32: u32) -> RollingAdler32 { - let a = adler32 & 0xFFFF; - let b = adler32 >> 16; - RollingAdler32 { a, b } - } - - /// Convenience function initializing a context from the hash of a buffer. - pub fn from_buffer(buffer: &[u8]) -> RollingAdler32 { - let mut hash = RollingAdler32::new(); - hash.update_buffer(buffer); - hash - } - - /// Returns the current hash. - pub fn hash(&self) -> u32 { - (self.b << 16) | self.a - } - - /// Removes the given `byte` that was fed to the algorithm `size` bytes ago. - pub fn remove(&mut self, size: usize, byte: u8) { - let byte = u32::from(byte); - self.a = (self.a + BASE - byte) % BASE; - self.b = ((self.b + BASE - 1) - .wrapping_add(BASE.wrapping_sub(size as u32) - .wrapping_mul(byte))) % BASE; - } - - /// Feeds a new `byte` to the algorithm to update the hash. - pub fn update(&mut self, byte: u8) { - let byte = u32::from(byte); - self.a = (self.a + byte) % BASE; - self.b = (self.b + self.a) % BASE; - } - - /// Feeds a vector of bytes to the algorithm to update the hash. - pub fn update_buffer(&mut self, buffer: &[u8]) { - let len = buffer.len(); - - // in case user likes doing a byte at a time, keep it fast - if len == 1 { - self.update(buffer[0]); - return; - } - - // in case short lengths are provided, keep it somewhat fast - if len < 16 { - for byte in buffer.iter().take(len) { - self.a += u32::from(*byte); - self.b += self.a; - } - if self.a >= BASE { - self.a -= BASE; - } - self.b %= BASE; - return; - } - - let mut pos = 0; - - // do length NMAX blocks -- requires just one modulo operation; - while pos + NMAX <= len { - let end = pos + NMAX; - while pos < end { - // 16 sums unrolled - do16(&mut self.a, &mut self.b, &buffer[pos..pos + 16]); - pos += 16; - } - self.a %= BASE; - self.b %= BASE; - } - - // do remaining bytes (less than NMAX, still just one modulo) - if pos < len { // avoid modulos if none remaining - while len - pos >= 16 { - do16(&mut self.a, &mut self.b, &buffer[pos..pos + 16]); - pos += 16; - } - while len - pos > 0 { - self.a += u32::from(buffer[pos]); - self.b += self.a; - pos += 1; - } - self.a %= BASE; - self.b %= BASE; - } - } -} - -/// Consume a Read object and returns the Adler32 hash. -pub fn adler32(mut reader: R) -> io::Result { - let mut hash = RollingAdler32::new(); - let mut buffer = [0u8; NMAX]; - let mut read = try!(reader.read(&mut buffer)); - while read > 0 { - hash.update_buffer(&buffer[..read]); - read = try!(reader.read(&mut buffer)); - } - Ok(hash.hash()) -} - -#[cfg(test)] -mod test { - use rand; - use rand::Rng; - use std::io; - - use super::{BASE, adler32, RollingAdler32}; - - fn adler32_slow(reader: R) -> io::Result { - let mut a: u32 = 1; - let mut b: u32 = 0; - - for byte in reader.bytes() { - let byte = try!(byte) as u32; - a = (a + byte) % BASE; - b = (b + a) % BASE; - } - - Ok((b << 16) | a) - } - - #[test] - fn testvectors() { - fn do_test(v: u32, bytes: &[u8]) { - let mut hash = RollingAdler32::new(); - hash.update_buffer(&bytes); - assert_eq!(hash.hash(), v); - - let r = io::Cursor::new(bytes); - assert_eq!(adler32(r).unwrap(), v); - } - do_test(0x00000001, b""); - do_test(0x00620062, b"a"); - do_test(0x024d0127, b"abc"); - do_test(0x29750586, b"message digest"); - do_test(0x90860b20, b"abcdefghijklmnopqrstuvwxyz"); - do_test(0x8adb150c, b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ - abcdefghijklmnopqrstuvwxyz\ - 0123456789"); - do_test(0x97b61069, b"1234567890123456789012345678901234567890\ - 1234567890123456789012345678901234567890"); - do_test(0xD6251498, &[255; 64000]); - } - - #[test] - fn compare() { - let mut rng = rand::thread_rng(); - let mut data = vec![0u8; 5589]; - for size in [0, 1, 3, 4, 5, 31, 32, 33, 67, - 5550, 5552, 5553, 5568, 5584, 5589].iter().cloned() { - rng.fill_bytes(&mut data[..size]); - let r1 = io::Cursor::new(&data[..size]); - let r2 = r1.clone(); - if adler32_slow(r1).unwrap() != adler32(r2).unwrap() { - panic!("Comparison failed, size={}", size); - } - } - } - - #[test] - fn rolling() { - assert_eq!(RollingAdler32::from_value(0x01020304).hash(), 0x01020304); - - fn do_test(a: &[u8], b: &[u8]) { - let mut total = Vec::with_capacity(a.len() + b.len()); - total.extend(a); - total.extend(b); - let mut h = RollingAdler32::from_buffer(&total[..(b.len())]); - for i in 0..(a.len()) { - h.remove(b.len(), a[i]); - h.update(total[b.len() + i]); - } - assert_eq!(h.hash(), adler32(b).unwrap()); - } - do_test(b"a", b"b"); - do_test(b"", b"this a test"); - do_test(b"th", b"is a test"); - do_test(b"this a ", b"test"); - } - - #[test] - fn long_window_remove() { - let mut hash = RollingAdler32::new(); - let w = 65536; - assert!(w as u32 > BASE); - - let mut bytes = vec![0; w*3]; - for (i, b) in bytes.iter_mut().enumerate() { - *b = i as u8; - } - - for (i, b) in bytes.iter().enumerate() { - if i >= w { - hash.remove(w, bytes[i - w]); - } - hash.update(*b); - if i > 0 && i % w == 0 { - assert_eq!(hash.hash(), 0x433a8772); - } - } - assert_eq!(hash.hash(), 0xbbba8772); - } -} diff --git a/third_party/cargo/vendor/adler32-1.2.0/.cargo-checksum.json b/third_party/cargo/vendor/adler32-1.2.0/.cargo-checksum.json new file mode 100644 index 0000000..9770265 --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"9e33701960053fa4c3fe2e5700bdd1fc17c6a7ff3d1cd617cb4f23cc01123a0c","LICENSE":"f5af8beef8f5f88f1b78494703bbfa019c4f3630ac111344390d6f9975ab22ed","README.md":"022d9b80f7ecec822a9f005f311d990f94a061970e7b982c85978675ff48de17","src/bench.rs":"bf3353d119660f44e4c2ef06d34c74e9585984cd7a82df609d51250476bdf2d0","src/lib.rs":"4f203fd48b12052f950213249a55db0b1c6cde93fe3bdf26b70a6eb42c6c9dee"},"package":"aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"} \ No newline at end of file diff --git a/third_party/cargo/vendor/adler32-1.2.0/BUILD.bazel b/third_party/cargo/vendor/adler32-1.2.0/BUILD.bazel new file mode 100644 index 0000000..8dc4725 --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/BUILD.bazel @@ -0,0 +1,57 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Zlib from expression "Zlib" +]) + +# Generated Targets + +# Unsupported target "bench" with type "bench" omitted + +rust_library( + name = "adler32", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.2.0", + # buildifier: leave-alone + deps = [ + ], +) diff --git a/third_party/cargo/vendor/adler32-1.2.0/Cargo.toml b/third_party/cargo/vendor/adler32-1.2.0/Cargo.toml new file mode 100644 index 0000000..749fabd --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/Cargo.toml @@ -0,0 +1,61 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "adler32" +version = "1.2.0" +authors = ["Remi Rampin "] +description = "Minimal Adler32 implementation for Rust." +documentation = "https://docs.rs/adler32/" +readme = "README.md" +keywords = ["adler32", "hash", "rolling"] +license = "Zlib" +repository = "https://github.com/remram44/adler32-rs" + +[lib] +bench = false + +[[bench]] +name = "bench" +path = "src/bench.rs" +harness = false +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.getrandom] +version = "0.1" +features = ["wasm-bindgen"] + +[dev-dependencies.humansize] +version = "1.1" + +[dev-dependencies.rand] +version = "0.7" + +[features] +default = ["std"] +rustc-dep-of-std = ["core", "compiler_builtins"] +std = [] +[target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen] +version = "0.2.63" + +[target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test] +version = "0.3" diff --git a/third_party/cargo/vendor/adler32-1.2.0/LICENSE b/third_party/cargo/vendor/adler32-1.2.0/LICENSE new file mode 100644 index 0000000..18419d4 --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/LICENSE @@ -0,0 +1,43 @@ +Copyright notice for the Rust port: + + (C) 2016 Remi Rampin and adler32-rs contributors + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +Copyright notice for the original C code from the zlib project: + + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/third_party/cargo/vendor/adler32-1.2.0/README.md b/third_party/cargo/vendor/adler32-1.2.0/README.md new file mode 100644 index 0000000..2a5239a --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/README.md @@ -0,0 +1,17 @@ +[![Build Status](https://github.com/remram44/adler32-rs/workflows/Test/badge.svg)](https://github.com/remram44/adler32-rs/actions) +[![Win Build](https://ci.appveyor.com/api/projects/status/ekyg20rd6rwrus64/branch/master?svg=true)](https://ci.appveyor.com/project/remram44/adler32-rs) +[![Crates.io](https://img.shields.io/crates/v/adler32.svg)](https://crates.io/crates/adler32) +[![Documentation](https://docs.rs/adler32/badge.svg)](https://docs.rs/adler32) +[![License](https://img.shields.io/crates/l/adler32.svg)](https://github.com/remram44/adler32-rs/blob/master/LICENSE) + +What is this? +============= + +It is an implementation of the [Adler32 rolling hash algorithm](https://en.wikipedia.org/wiki/Adler-32) in the [Rust programming language](https://www.rust-lang.org/). + +It is adapted from Jean-Loup Gailly's and Mark Adler's [original implementation in zlib](https://github.com/madler/zlib/blob/2fa463bacfff79181df1a5270fb67cc679a53e71/adler32.c). + + +#### Minimum Supported Version of Rust (MSRV) + +`adler32-rs` can be built with Rust version 1.33 or later. This version may be raised in the future but that will be accompanied by a minor version increase. diff --git a/third_party/cargo/vendor/adler32-1.2.0/src/bench.rs b/third_party/cargo/vendor/adler32-1.2.0/src/bench.rs new file mode 100644 index 0000000..a3d23d6 --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/src/bench.rs @@ -0,0 +1,30 @@ +use adler32::RollingAdler32; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use humansize::{file_size_opts, FileSize}; +use rand::Rng; + +fn bench_update_buffer(c: &mut Criterion) { + let mut rng = rand::thread_rng(); + let mut group = c.benchmark_group("update_buffer"); + for &size in [512, 100 * 1024].iter() { + let mut adler = RollingAdler32::new(); + let formatted_size = size.file_size(file_size_opts::BINARY).unwrap(); + let in_bytes = { + let mut in_bytes = vec![0u8; size]; + rng.fill(&mut in_bytes[..]); + in_bytes + }; + + group.throughput(Throughput::Bytes(size as u64)); + group.bench_with_input( + BenchmarkId::from_parameter(formatted_size), + &in_bytes, + |b, data| { + b.iter(|| adler.update_buffer(data)); + }, + ); + } +} + +criterion_group!(bench_default, bench_update_buffer); +criterion_main!(bench_default); diff --git a/third_party/cargo/vendor/adler32-1.2.0/src/lib.rs b/third_party/cargo/vendor/adler32-1.2.0/src/lib.rs new file mode 100644 index 0000000..d9db56c --- /dev/null +++ b/third_party/cargo/vendor/adler32-1.2.0/src/lib.rs @@ -0,0 +1,324 @@ +//! A minimal implementation of Adler32 for Rust. +//! +//! This provides the simple method adler32(), that exhausts a Read and +//! computes the Adler32 hash, as well as the RollingAdler32 struct, that can +//! build a hash byte-by-byte, allowing to 'forget' past bytes in a rolling +//! fashion. +//! +//! The adler32 code has been translated (as accurately as I could manage) from +//! the zlib implementation. + +#![forbid(unsafe_code)] +#![cfg_attr(not(feature = "std"), no_std)] + + +// adler32 algorithm and implementation taken from zlib; http://www.zlib.net/ +// It was translated into Rust as accurately as I could manage +// The (slow) reference was taken from Wikipedia; https://en.wikipedia.org/ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +*/ + +// largest prime smaller than 65536 +const BASE: u32 = 65521; + +// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 +const NMAX: usize = 5552; + +#[inline(always)] +fn do1(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { + *adler += u32::from(buf[0]); + *sum2 += *adler; +} + +#[inline(always)] +fn do2(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { + do1(adler, sum2, &buf[0..1]); + do1(adler, sum2, &buf[1..2]); +} + +#[inline(always)] +fn do4(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { + do2(adler, sum2, &buf[0..2]); + do2(adler, sum2, &buf[2..4]); +} + +#[inline(always)] +fn do8(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { + do4(adler, sum2, &buf[0..4]); + do4(adler, sum2, &buf[4..8]); +} + +#[inline(always)] +fn do16(adler: &mut u32, sum2: &mut u32, buf: &[u8]) { + do8(adler, sum2, &buf[0..8]); + do8(adler, sum2, &buf[8..16]); +} + +/// A rolling version of the Adler32 hash, which can 'forget' past bytes. +/// +/// Calling remove() will update the hash to the value it would have if that +/// past byte had never been fed to the algorithm. This allows you to get the +/// hash of a rolling window very efficiently. +#[derive(Clone)] +pub struct RollingAdler32 { + a: u32, + b: u32, +} + +impl Default for RollingAdler32 { + fn default() -> RollingAdler32 { + RollingAdler32::new() + } +} + +impl RollingAdler32 { + /// Creates an empty Adler32 context (with hash 1). + pub fn new() -> RollingAdler32 { + Self::from_value(1) + } + + /// Creates an Adler32 context with the given initial value. + pub fn from_value(adler32: u32) -> RollingAdler32 { + let a = adler32 & 0xFFFF; + let b = adler32 >> 16; + RollingAdler32 { a, b } + } + + /// Convenience function initializing a context from the hash of a buffer. + pub fn from_buffer(buffer: &[u8]) -> RollingAdler32 { + let mut hash = RollingAdler32::new(); + hash.update_buffer(buffer); + hash + } + + /// Returns the current hash. + pub fn hash(&self) -> u32 { + (self.b << 16) | self.a + } + + /// Removes the given `byte` that was fed to the algorithm `size` bytes ago. + pub fn remove(&mut self, size: usize, byte: u8) { + let byte = u32::from(byte); + self.a = (self.a + BASE - byte) % BASE; + self.b = ((self.b + BASE - 1) + .wrapping_add(BASE.wrapping_sub(size as u32).wrapping_mul(byte))) + % BASE; + } + + /// Feeds a new `byte` to the algorithm to update the hash. + pub fn update(&mut self, byte: u8) { + let byte = u32::from(byte); + self.a = (self.a + byte) % BASE; + self.b = (self.b + self.a) % BASE; + } + + /// Feeds a vector of bytes to the algorithm to update the hash. + pub fn update_buffer(&mut self, buffer: &[u8]) { + let len = buffer.len(); + + // in case user likes doing a byte at a time, keep it fast + if len == 1 { + self.update(buffer[0]); + return; + } + + // in case short lengths are provided, keep it somewhat fast + if len < 16 { + for byte in buffer.iter().take(len) { + self.a += u32::from(*byte); + self.b += self.a; + } + if self.a >= BASE { + self.a -= BASE; + } + self.b %= BASE; + return; + } + + let mut pos = 0; + + // do length NMAX blocks -- requires just one modulo operation; + while pos + NMAX <= len { + let end = pos + NMAX; + while pos < end { + // 16 sums unrolled + do16(&mut self.a, &mut self.b, &buffer[pos..pos + 16]); + pos += 16; + } + self.a %= BASE; + self.b %= BASE; + } + + // do remaining bytes (less than NMAX, still just one modulo) + if pos < len { + // avoid modulos if none remaining + while len - pos >= 16 { + do16(&mut self.a, &mut self.b, &buffer[pos..pos + 16]); + pos += 16; + } + while len - pos > 0 { + self.a += u32::from(buffer[pos]); + self.b += self.a; + pos += 1; + } + self.a %= BASE; + self.b %= BASE; + } + } +} + +/// Consume a Read object and returns the Adler32 hash. +#[cfg(feature = "std")] +pub fn adler32(mut reader: R) -> std::io::Result { + let mut hash = RollingAdler32::new(); + let mut buffer = [0u8; NMAX]; + let mut read = reader.read(&mut buffer)?; + while read > 0 { + hash.update_buffer(&buffer[..read]); + read = reader.read(&mut buffer)?; + } + Ok(hash.hash()) +} + +#[cfg(test)] +mod test { + use rand::Rng; + use std::io; + #[cfg(target_arch = "wasm32")] + use wasm_bindgen_test::wasm_bindgen_test; + + use super::{adler32, RollingAdler32, BASE}; + + fn adler32_slow(reader: R) -> io::Result { + let mut a: u32 = 1; + let mut b: u32 = 0; + + for byte in reader.bytes() { + let byte = byte? as u32; + a = (a + byte) % BASE; + b = (b + a) % BASE; + } + + Ok((b << 16) | a) + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn testvectors() { + fn do_test(v: u32, bytes: &[u8]) { + let mut hash = RollingAdler32::new(); + hash.update_buffer(&bytes); + assert_eq!(hash.hash(), v); + + let r = io::Cursor::new(bytes); + assert_eq!(adler32(r).unwrap(), v); + } + do_test(0x00000001, b""); + do_test(0x00620062, b"a"); + do_test(0x024d0127, b"abc"); + do_test(0x29750586, b"message digest"); + do_test(0x90860b20, b"abcdefghijklmnopqrstuvwxyz"); + do_test( + 0x8adb150c, + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789", + ); + do_test( + 0x97b61069, + b"1234567890123456789012345678901234567890\ + 1234567890123456789012345678901234567890", + ); + do_test(0xD6251498, &[255; 64000]); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn compare() { + let mut rng = rand::thread_rng(); + let mut data = vec![0u8; 5589]; + for size in [ + 0, 1, 3, 4, 5, 31, 32, 33, 67, 5550, 5552, 5553, 5568, 5584, 5589, + ] + .iter() + .cloned() + { + rng.fill(&mut data[..size]); + let r1 = io::Cursor::new(&data[..size]); + let r2 = r1.clone(); + if adler32_slow(r1).unwrap() != adler32(r2).unwrap() { + panic!("Comparison failed, size={}", size); + } + } + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn rolling() { + assert_eq!(RollingAdler32::from_value(0x01020304).hash(), 0x01020304); + + fn do_test(a: &[u8], b: &[u8]) { + let mut total = Vec::with_capacity(a.len() + b.len()); + total.extend(a); + total.extend(b); + let mut h = RollingAdler32::from_buffer(&total[..(b.len())]); + for i in 0..(a.len()) { + h.remove(b.len(), a[i]); + h.update(total[b.len() + i]); + } + assert_eq!(h.hash(), adler32(b).unwrap()); + } + do_test(b"a", b"b"); + do_test(b"", b"this a test"); + do_test(b"th", b"is a test"); + do_test(b"this a ", b"test"); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + fn long_window_remove() { + let mut hash = RollingAdler32::new(); + let w = 65536; + assert!(w as u32 > BASE); + + let mut bytes = vec![0; w * 3]; + for (i, b) in bytes.iter_mut().enumerate() { + *b = i as u8; + } + + for (i, b) in bytes.iter().enumerate() { + if i >= w { + hash.remove(w, bytes[i - w]); + } + hash.update(*b); + if i > 0 && i % w == 0 { + assert_eq!(hash.hash(), 0x433a8772); + } + } + assert_eq!(hash.hash(), 0xbbba8772); + } +} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/.cargo-checksum.json b/third_party/cargo/vendor/aho-corasick-0.7.10/.cargo-checksum.json deleted file mode 100644 index 94163ff..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"bf3140f591d5e16e2c178bfdc39bc2ea9fecf3b50963ff60343d3e5a68d024cc","DESIGN.md":"9065f33d818d1562244d36dc4781e2a351108030cee17f11c2ba512ca7b4c27e","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"f679a3a8fa99694e00e2ed8ec9cd6f7dc28eee36f47c472411744aabb0556d0b","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/ahocorasick.rs":"46c57a83a75a8f25fdf19a15deae10748d12b8af9445ae74700a546a92024608","src/automaton.rs":"ea3fc2648e026eac9f9969b0d457e49af7b4a40044379ce010d054f22afbc98f","src/buffer.rs":"0641828d1058b9c1c16e8e2445ce05c94b0ad2d97736a7e3cd8b913fa8edd7fd","src/byte_frequencies.rs":"2fb85b381c038c1e44ce94294531cdcd339dca48b1e61f41455666e802cbbc9e","src/classes.rs":"166c9f15c9a2e370e2bc9a9e1620bb2db13df52edfde9a0db1f20144519a7e72","src/dfa.rs":"e34f485a7c3257d2edee16fcdb2a5586aa0d2aa9e34d624288eb2b5a0f7cc65b","src/error.rs":"36dbf2cefbfaa8a69186551320dbff023d3e82780a6c925e87c3e3997b967e66","src/lib.rs":"a2a65d72cbe1eed1964c3fb080e5fa54245ab208a3c855531c1036f05e073452","src/nfa.rs":"6e8fe7633033c378e5487604a2772af3fc2eca011fe374fe0b6d6cee98198f58","src/packed/api.rs":"6c65dfa177b7d7b79f90a048f260bec7f817126c693b85f49704c7d2ecf5f646","src/packed/mod.rs":"29c76ad3cbb1f831140cefac7a27fb504ac4af4f454975a571965b48aad417eb","src/packed/pattern.rs":"b88c57af057997da0a5a06f4c5604a7e598c20acfc11c15cd8977727f6e1cf9c","src/packed/rabinkarp.rs":"b3242a8631ea5607163dcbb641e4ac9c6da26774378da1e51651b0ab5656b390","src/packed/teddy/README.md":"5819f40d221af93288e705eadef5393a41d7a0900881b4d676e01fd65d5adf15","src/packed/teddy/compile.rs":"5d7de6a45a84bb2322647a6de7a7b1573837b9222b16e348f023b8d47e0a5130","src/packed/teddy/mod.rs":"f63db3419b1d378929bf0bc1f0e3b909ff3c38b9f2b6e86ba4546b8f39907cd3","src/packed/teddy/runtime.rs":"0a1250ea73159b3be6e0fa9a3f55ecedbb2cb90cb798d1709e9f5ee48f8855d5","src/packed/tests.rs":"0b52ab9eef73a1a4f141f475a9fa98e54d447104aa69acba3a7f8248ce7164b2","src/packed/vector.rs":"ab3c0535fca5f09198d58cbfae44c292aeb3ce44bc92bca36d30dc72963639fc","src/prefilter.rs":"f615e929629f9356fb779a4456a0b6b1ee139960029df71d41620bf3fed9282d","src/state_id.rs":"50958ca2b089d775fb4e49a64950e2f1e8a4af1772fe782ae3715a7745dcc6d7","src/tests.rs":"7458d220c78bbc382c1332e0a222f7e47b6b8ff1fac666d46db4c3a9e63cef4c"},"package":"8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"} \ No newline at end of file diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/BUILD.bazel b/third_party/cargo/vendor/aho-corasick-0.7.10/BUILD.bazel deleted file mode 100644 index f2e75a1..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/BUILD.bazel +++ /dev/null @@ -1,56 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "unencumbered", # Unlicense from expression "Unlicense OR MIT" -]) - -# Generated Targets - -rust_library( - name = "aho_corasick", - srcs = glob(["**/*.rs"]), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.7.10", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/memchr-2.3.3:memchr", - ], -) diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/Cargo.toml b/third_party/cargo/vendor/aho-corasick-0.7.10/Cargo.toml deleted file mode 100644 index b240ec3..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "aho-corasick" -version = "0.7.10" -authors = ["Andrew Gallant "] -exclude = ["/aho-corasick-debug", "/ci/*", "/.travis.yml", "/appveyor.yml"] -autotests = false -description = "Fast multiple substring searching." -homepage = "https://github.com/BurntSushi/aho-corasick" -readme = "README.md" -keywords = ["string", "search", "text", "aho", "multi"] -categories = ["text-processing"] -license = "Unlicense/MIT" -repository = "https://github.com/BurntSushi/aho-corasick" -[profile.bench] -debug = true - -[profile.release] -debug = true - -[lib] -name = "aho_corasick" -[dependencies.memchr] -version = "2.2.0" -default-features = false -[dev-dependencies.doc-comment] -version = "0.3.1" - -[features] -default = ["std"] -std = ["memchr/use_std"] diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/README.md b/third_party/cargo/vendor/aho-corasick-0.7.10/README.md deleted file mode 100644 index 9ae3427..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/README.md +++ /dev/null @@ -1,186 +0,0 @@ -aho-corasick -============ -A library for finding occurrences of many patterns at once with SIMD -acceleration in some cases. This library provides multiple pattern -search principally through an implementation of the -[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm), -which builds a finite state machine for executing searches in linear time. -Features include case insensitive matching, overlapping matches and search & -replace in streams. - -[![Build status](https://github.com/BurntSushi/aho-corasick/workflows/ci/badge.svg)](https://github.com/BurntSushi/aho-corasick/actions) -[![](http://meritbadge.herokuapp.com/aho-corasick)](https://crates.io/crates/aho-corasick) - -Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). - - -### Documentation - -https://docs.rs/aho-corasick - - -### Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -aho-corasick = "0.7" -``` - -and this to your crate root (if you're using Rust 2015): - -```rust -extern crate aho_corasick; -``` - - -### Example: basic searching - -This example shows how to search for occurrences of multiple patterns -simultaneously. Each match includes the pattern that matched along with the -byte offsets of the match. - -```rust -use aho_corasick::AhoCorasick; - -let patterns = &["apple", "maple", "Snapple"]; -let haystack = "Nobody likes maple in their apple flavored Snapple."; - -let ac = AhoCorasick::new(patterns); -let mut matches = vec![]; -for mat in ac.find_iter(haystack) { - matches.push((mat.pattern(), mat.start(), mat.end())); -} -assert_eq!(matches, vec![ - (1, 13, 18), - (0, 28, 33), - (2, 43, 50), -]); -``` - - -### Example: case insensitivity - -This is like the previous example, but matches `Snapple` case insensitively -using `AhoCorasickBuilder`: - -```rust -use aho_corasick::AhoCorasickBuilder; - -let patterns = &["apple", "maple", "snapple"]; -let haystack = "Nobody likes maple in their apple flavored Snapple."; - -let ac = AhoCorasickBuilder::new() - .ascii_case_insensitive(true) - .build(patterns); -let mut matches = vec![]; -for mat in ac.find_iter(haystack) { - matches.push((mat.pattern(), mat.start(), mat.end())); -} -assert_eq!(matches, vec![ - (1, 13, 18), - (0, 28, 33), - (2, 43, 50), -]); -``` - - -### Example: replacing matches in a stream - -This example shows how to execute a search and replace on a stream without -loading the entire stream into memory first. - -```rust -use aho_corasick::AhoCorasick; - -let patterns = &["fox", "brown", "quick"]; -let replace_with = &["sloth", "grey", "slow"]; - -// In a real example, these might be `std::fs::File`s instead. All you need to -// do is supply a pair of `std::io::Read` and `std::io::Write` implementations. -let rdr = "The quick brown fox."; -let mut wtr = vec![]; - -let ac = AhoCorasick::new(patterns); -ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)?; -assert_eq!(b"The slow grey sloth.".to_vec(), wtr); -``` - - -### Example: finding the leftmost first match - -In the textbook description of Aho-Corasick, its formulation is typically -structured such that it reports all possible matches, even when they overlap -with another. In many cases, overlapping matches may not be desired, such as -the case of finding all successive non-overlapping matches like you might with -a standard regular expression. - -Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do -this doesn't always work in the expected way, since it will report matches as -soon as they are seen. For example, consider matching the regex `Samwise|Sam` -against the text `Samwise`. Most regex engines (that are Perl-like, or -non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick -algorithm modified for reporting non-overlapping matches will report `Sam`. - -A novel contribution of this library is the ability to change the match -semantics of Aho-Corasick (without additional search time overhead) such that -`Samwise` is reported instead. For example, here's the standard approach: - -```rust -use aho_corasick::AhoCorasick; - -let patterns = &["Samwise", "Sam"]; -let haystack = "Samwise"; - -let ac = AhoCorasick::new(patterns); -let mat = ac.find(haystack).expect("should have a match"); -assert_eq!("Sam", &haystack[mat.start()..mat.end()]); -``` - -And now here's the leftmost-first version, which matches how a Perl-like -regex will work: - -```rust -use aho_corasick::{AhoCorasickBuilder, MatchKind}; - -let patterns = &["Samwise", "Sam"]; -let haystack = "Samwise"; - -let ac = AhoCorasickBuilder::new() - .match_kind(MatchKind::LeftmostFirst) - .build(patterns); -let mat = ac.find(haystack).expect("should have a match"); -assert_eq!("Samwise", &haystack[mat.start()..mat.end()]); -``` - -In addition to leftmost-first semantics, this library also supports -leftmost-longest semantics, which match the POSIX behavior of a regular -expression alternation. See `MatchKind` in the docs for more details. - - -### Minimum Rust version policy - -This crate's minimum supported `rustc` version is `1.28.0`. - -The current policy is that the minimum Rust version required to use this crate -can be increased in minor version updates. For example, if `crate 1.0` requires -Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust -1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum -version of Rust. - -In general, this crate will be conservative with respect to the minimum -supported version of Rust. - - -### Future work - -Here are some plans for the future: - -* Assuming the current API is sufficient, I'd like to commit to it and release - a `1.0` version of this crate some time in the next 6-12 months. -* Support stream searching with leftmost match semantics. Currently, only - standard match semantics are supported. Getting this right seems possible, - but is tricky since the match state needs to be propagated through multiple - searches. (With standard semantics, as soon as a match is seen the search - ends.) diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/buffer.rs b/third_party/cargo/vendor/aho-corasick-0.7.10/src/buffer.rs deleted file mode 100644 index 1008196..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/buffer.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::cmp; -use std::io; -use std::ptr; - -/// The default buffer capacity that we use for the stream buffer. -const DEFAULT_BUFFER_CAPACITY: usize = 8 * (1 << 10); // 8 KB - -/// A fairly simple roll buffer for supporting stream searches. -/// -/// This buffer acts as a temporary place to store a fixed amount of data when -/// reading from a stream. Its central purpose is to allow "rolling" some -/// suffix of the data to the beginning of the buffer before refilling it with -/// more data from the stream. For example, let's say we are trying to match -/// "foobar" on a stream. When we report the match, we'd like to not only -/// report the correct offsets at which the match occurs, but also the matching -/// bytes themselves. So let's say our stream is a file with the following -/// contents: `test test foobar test test`. Now assume that we happen to read -/// the aforementioned file in two chunks: `test test foo` and `bar test test`. -/// Naively, it would not be possible to report a single contiguous `foobar` -/// match, but this roll buffer allows us to do that. Namely, after the second -/// read, the contents of the buffer should be `st foobar test test`, where the -/// search should ultimately resume immediately after `foo`. (The prefix `st ` -/// is included because the roll buffer saves N bytes at the end of the buffer, -/// where N is the maximum possible length of a match.) -/// -/// A lot of the logic for dealing with this is unfortunately split out between -/// this roll buffer and the `StreamChunkIter`. -#[derive(Debug)] -pub struct Buffer { - /// The raw buffer contents. This has a fixed size and never increases. - buf: Vec, - /// The minimum size of the buffer, which is equivalent to the maximum - /// possible length of a match. This corresponds to the amount that we - /// roll - min: usize, - /// The end of the contents of this buffer. - end: usize, -} - -impl Buffer { - /// Create a new buffer for stream searching. The minimum buffer length - /// given should be the size of the maximum possible match length. - pub fn new(min_buffer_len: usize) -> Buffer { - let min = cmp::max(1, min_buffer_len); - // The minimum buffer amount is also the amount that we roll our - // buffer in order to support incremental searching. To this end, - // our actual capacity needs to be at least 1 byte bigger than our - // minimum amount, otherwise we won't have any overlap. In actuality, - // we want our buffer to be a bit bigger than that for performance - // reasons, so we set a lower bound of `8 * min`. - // - // TODO: It would be good to find a way to test the streaming - // implementation with the minimal buffer size. - let capacity = cmp::max(min * 8, DEFAULT_BUFFER_CAPACITY); - Buffer { buf: vec![0; capacity], min, end: 0 } - } - - /// Return the contents of this buffer. - #[inline] - pub fn buffer(&self) -> &[u8] { - &self.buf[..self.end] - } - - /// Return the minimum size of the buffer. The only way a buffer may be - /// smaller than this is if the stream itself contains less than the - /// minimum buffer amount. - #[inline] - pub fn min_buffer_len(&self) -> usize { - self.min - } - - /// Return the total length of the contents in the buffer. - #[inline] - pub fn len(&self) -> usize { - self.end - } - - /// Return all free capacity in this buffer. - fn free_buffer(&mut self) -> &mut [u8] { - &mut self.buf[self.end..] - } - - /// Refill the contents of this buffer by reading as much as possible into - /// this buffer's free capacity. If no more bytes could be read, then this - /// returns false. Otherwise, this reads until it has filled the buffer - /// past the minimum amount. - pub fn fill(&mut self, mut rdr: R) -> io::Result { - let mut readany = false; - loop { - let readlen = rdr.read(self.free_buffer())?; - if readlen == 0 { - return Ok(readany); - } - readany = true; - self.end += readlen; - if self.len() >= self.min { - return Ok(true); - } - } - } - - /// Roll the contents of the buffer so that the suffix of this buffer is - /// moved to the front and all other contents are dropped. The size of the - /// suffix corresponds precisely to the minimum buffer length. - /// - /// This should only be called when the entire contents of this buffer have - /// been searched. - pub fn roll(&mut self) { - let roll_start = self - .end - .checked_sub(self.min) - .expect("buffer capacity should be bigger than minimum amount"); - let roll_len = self.min; - - assert!(roll_start + roll_len <= self.end); - unsafe { - // SAFETY: A buffer contains Copy data, so there's no problem - // moving it around. Safety also depends on our indices being in - // bounds, which they always should be, given the assert above. - // - // TODO: Switch to [T]::copy_within once our MSRV is high enough. - ptr::copy( - self.buf[roll_start..].as_ptr(), - self.buf.as_mut_ptr(), - roll_len, - ); - } - self.end = roll_len; - } -} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/dfa.rs b/third_party/cargo/vendor/aho-corasick-0.7.10/src/dfa.rs deleted file mode 100644 index 1bf37d5..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/dfa.rs +++ /dev/null @@ -1,709 +0,0 @@ -use std::mem::size_of; - -use ahocorasick::MatchKind; -use automaton::Automaton; -use classes::ByteClasses; -use error::Result; -use nfa::{PatternID, PatternLength, NFA}; -use prefilter::{Prefilter, PrefilterObj, PrefilterState}; -use state_id::{dead_id, fail_id, premultiply_overflow_error, StateID}; -use Match; - -#[derive(Clone, Debug)] -pub enum DFA { - Standard(Standard), - ByteClass(ByteClass), - Premultiplied(Premultiplied), - PremultipliedByteClass(PremultipliedByteClass), -} - -impl DFA { - fn repr(&self) -> &Repr { - match *self { - DFA::Standard(ref dfa) => dfa.repr(), - DFA::ByteClass(ref dfa) => dfa.repr(), - DFA::Premultiplied(ref dfa) => dfa.repr(), - DFA::PremultipliedByteClass(ref dfa) => dfa.repr(), - } - } - - pub fn match_kind(&self) -> &MatchKind { - &self.repr().match_kind - } - - pub fn heap_bytes(&self) -> usize { - self.repr().heap_bytes - } - - pub fn max_pattern_len(&self) -> usize { - self.repr().max_pattern_len - } - - pub fn pattern_count(&self) -> usize { - self.repr().pattern_count - } - - pub fn start_state(&self) -> S { - self.repr().start_id - } - - #[inline(always)] - pub fn overlapping_find_at( - &self, - prestate: &mut PrefilterState, - haystack: &[u8], - at: usize, - state_id: &mut S, - match_index: &mut usize, - ) -> Option { - match *self { - DFA::Standard(ref dfa) => dfa.overlapping_find_at( - prestate, - haystack, - at, - state_id, - match_index, - ), - DFA::ByteClass(ref dfa) => dfa.overlapping_find_at( - prestate, - haystack, - at, - state_id, - match_index, - ), - DFA::Premultiplied(ref dfa) => dfa.overlapping_find_at( - prestate, - haystack, - at, - state_id, - match_index, - ), - DFA::PremultipliedByteClass(ref dfa) => dfa.overlapping_find_at( - prestate, - haystack, - at, - state_id, - match_index, - ), - } - } - - #[inline(always)] - pub fn earliest_find_at( - &self, - prestate: &mut PrefilterState, - haystack: &[u8], - at: usize, - state_id: &mut S, - ) -> Option { - match *self { - DFA::Standard(ref dfa) => { - dfa.earliest_find_at(prestate, haystack, at, state_id) - } - DFA::ByteClass(ref dfa) => { - dfa.earliest_find_at(prestate, haystack, at, state_id) - } - DFA::Premultiplied(ref dfa) => { - dfa.earliest_find_at(prestate, haystack, at, state_id) - } - DFA::PremultipliedByteClass(ref dfa) => { - dfa.earliest_find_at(prestate, haystack, at, state_id) - } - } - } - - #[inline(always)] - pub fn find_at_no_state( - &self, - prestate: &mut PrefilterState, - haystack: &[u8], - at: usize, - ) -> Option { - match *self { - DFA::Standard(ref dfa) => { - dfa.find_at_no_state(prestate, haystack, at) - } - DFA::ByteClass(ref dfa) => { - dfa.find_at_no_state(prestate, haystack, at) - } - DFA::Premultiplied(ref dfa) => { - dfa.find_at_no_state(prestate, haystack, at) - } - DFA::PremultipliedByteClass(ref dfa) => { - dfa.find_at_no_state(prestate, haystack, at) - } - } - } -} - -#[derive(Clone, Debug)] -pub struct Standard(Repr); - -impl Standard { - fn repr(&self) -> &Repr { - &self.0 - } -} - -impl Automaton for Standard { - type ID = S; - - fn match_kind(&self) -> &MatchKind { - &self.repr().match_kind - } - - fn anchored(&self) -> bool { - self.repr().anchored - } - - fn prefilter(&self) -> Option<&dyn Prefilter> { - self.repr().prefilter.as_ref().map(|p| p.as_ref()) - } - - fn start_state(&self) -> S { - self.repr().start_id - } - - fn is_valid(&self, id: S) -> bool { - id.to_usize() < self.repr().state_count - } - - fn is_match_state(&self, id: S) -> bool { - self.repr().is_match_state(id) - } - - fn is_match_or_dead_state(&self, id: S) -> bool { - self.repr().is_match_or_dead_state(id) - } - - fn get_match( - &self, - id: S, - match_index: usize, - end: usize, - ) -> Option { - self.repr().get_match(id, match_index, end) - } - - fn match_count(&self, id: S) -> usize { - self.repr().match_count(id) - } - - fn next_state(&self, current: S, input: u8) -> S { - let o = current.to_usize() * 256 + input as usize; - self.repr().trans[o] - } -} - -#[derive(Clone, Debug)] -pub struct ByteClass(Repr); - -impl ByteClass { - fn repr(&self) -> &Repr { - &self.0 - } -} - -impl Automaton for ByteClass { - type ID = S; - - fn match_kind(&self) -> &MatchKind { - &self.repr().match_kind - } - - fn anchored(&self) -> bool { - self.repr().anchored - } - - fn prefilter(&self) -> Option<&dyn Prefilter> { - self.repr().prefilter.as_ref().map(|p| p.as_ref()) - } - - fn start_state(&self) -> S { - self.repr().start_id - } - - fn is_valid(&self, id: S) -> bool { - id.to_usize() < self.repr().state_count - } - - fn is_match_state(&self, id: S) -> bool { - self.repr().is_match_state(id) - } - - fn is_match_or_dead_state(&self, id: S) -> bool { - self.repr().is_match_or_dead_state(id) - } - - fn get_match( - &self, - id: S, - match_index: usize, - end: usize, - ) -> Option { - self.repr().get_match(id, match_index, end) - } - - fn match_count(&self, id: S) -> usize { - self.repr().match_count(id) - } - - fn next_state(&self, current: S, input: u8) -> S { - let alphabet_len = self.repr().byte_classes.alphabet_len(); - let input = self.repr().byte_classes.get(input); - let o = current.to_usize() * alphabet_len + input as usize; - self.repr().trans[o] - } -} - -#[derive(Clone, Debug)] -pub struct Premultiplied(Repr); - -impl Premultiplied { - fn repr(&self) -> &Repr { - &self.0 - } -} - -impl Automaton for Premultiplied { - type ID = S; - - fn match_kind(&self) -> &MatchKind { - &self.repr().match_kind - } - - fn anchored(&self) -> bool { - self.repr().anchored - } - - fn prefilter(&self) -> Option<&dyn Prefilter> { - self.repr().prefilter.as_ref().map(|p| p.as_ref()) - } - - fn start_state(&self) -> S { - self.repr().start_id - } - - fn is_valid(&self, id: S) -> bool { - (id.to_usize() / 256) < self.repr().state_count - } - - fn is_match_state(&self, id: S) -> bool { - self.repr().is_match_state(id) - } - - fn is_match_or_dead_state(&self, id: S) -> bool { - self.repr().is_match_or_dead_state(id) - } - - fn get_match( - &self, - id: S, - match_index: usize, - end: usize, - ) -> Option { - if id > self.repr().max_match { - return None; - } - self.repr() - .matches - .get(id.to_usize() / 256) - .and_then(|m| m.get(match_index)) - .map(|&(id, len)| Match { pattern: id, len, end }) - } - - fn match_count(&self, id: S) -> usize { - let o = id.to_usize() / 256; - self.repr().matches[o].len() - } - - fn next_state(&self, current: S, input: u8) -> S { - let o = current.to_usize() + input as usize; - self.repr().trans[o] - } -} - -#[derive(Clone, Debug)] -pub struct PremultipliedByteClass(Repr); - -impl PremultipliedByteClass { - fn repr(&self) -> &Repr { - &self.0 - } -} - -impl Automaton for PremultipliedByteClass { - type ID = S; - - fn match_kind(&self) -> &MatchKind { - &self.repr().match_kind - } - - fn anchored(&self) -> bool { - self.repr().anchored - } - - fn prefilter(&self) -> Option<&dyn Prefilter> { - self.repr().prefilter.as_ref().map(|p| p.as_ref()) - } - - fn start_state(&self) -> S { - self.repr().start_id - } - - fn is_valid(&self, id: S) -> bool { - (id.to_usize() / self.repr().alphabet_len()) < self.repr().state_count - } - - fn is_match_state(&self, id: S) -> bool { - self.repr().is_match_state(id) - } - - fn is_match_or_dead_state(&self, id: S) -> bool { - self.repr().is_match_or_dead_state(id) - } - - fn get_match( - &self, - id: S, - match_index: usize, - end: usize, - ) -> Option { - if id > self.repr().max_match { - return None; - } - self.repr() - .matches - .get(id.to_usize() / self.repr().alphabet_len()) - .and_then(|m| m.get(match_index)) - .map(|&(id, len)| Match { pattern: id, len, end }) - } - - fn match_count(&self, id: S) -> usize { - let o = id.to_usize() / self.repr().alphabet_len(); - self.repr().matches[o].len() - } - - fn next_state(&self, current: S, input: u8) -> S { - let input = self.repr().byte_classes.get(input); - let o = current.to_usize() + input as usize; - self.repr().trans[o] - } -} - -#[derive(Clone, Debug)] -pub struct Repr { - match_kind: MatchKind, - anchored: bool, - premultiplied: bool, - start_id: S, - /// The length, in bytes, of the longest pattern in this automaton. This - /// information is useful for keeping correct buffer sizes when searching - /// on streams. - max_pattern_len: usize, - /// The total number of patterns added to this automaton. This includes - /// patterns that may never match. - pattern_count: usize, - state_count: usize, - max_match: S, - /// The number of bytes of heap used by this NFA's transition table. - heap_bytes: usize, - /// A prefilter for quickly detecting candidate matchs, if pertinent. - prefilter: Option, - byte_classes: ByteClasses, - trans: Vec, - matches: Vec>, -} - -impl Repr { - /// Returns the total alphabet size for this DFA. - /// - /// If byte classes are enabled, then this corresponds to the number of - /// equivalence classes. If they are disabled, then this is always 256. - fn alphabet_len(&self) -> usize { - self.byte_classes.alphabet_len() - } - - /// Returns true only if the given state is a match state. - fn is_match_state(&self, id: S) -> bool { - id <= self.max_match && id > dead_id() - } - - /// Returns true only if the given state is either a dead state or a match - /// state. - fn is_match_or_dead_state(&self, id: S) -> bool { - id <= self.max_match - } - - /// Get the ith match for the given state, where the end position of a - /// match was found at `end`. - /// - /// # Panics - /// - /// The caller must ensure that the given state identifier is valid, - /// otherwise this may panic. The `match_index` need not be valid. That is, - /// if the given state has no matches then this returns `None`. - fn get_match( - &self, - id: S, - match_index: usize, - end: usize, - ) -> Option { - if id > self.max_match { - return None; - } - self.matches - .get(id.to_usize()) - .and_then(|m| m.get(match_index)) - .map(|&(id, len)| Match { pattern: id, len, end }) - } - - /// Return the total number of matches for the given state. - /// - /// # Panics - /// - /// The caller must ensure that the given identifier is valid, or else - /// this panics. - fn match_count(&self, id: S) -> usize { - self.matches[id.to_usize()].len() - } - - /// Get the next state given `from` as the current state and `byte` as the - /// current input byte. - fn next_state(&self, from: S, byte: u8) -> S { - let alphabet_len = self.alphabet_len(); - let byte = self.byte_classes.get(byte); - self.trans[from.to_usize() * alphabet_len + byte as usize] - } - - /// Set the `byte` transition for the `from` state to point to `to`. - fn set_next_state(&mut self, from: S, byte: u8, to: S) { - let alphabet_len = self.alphabet_len(); - let byte = self.byte_classes.get(byte); - self.trans[from.to_usize() * alphabet_len + byte as usize] = to; - } - - /// Swap the given states in place. - fn swap_states(&mut self, id1: S, id2: S) { - assert!(!self.premultiplied, "can't swap states in premultiplied DFA"); - - let o1 = id1.to_usize() * self.alphabet_len(); - let o2 = id2.to_usize() * self.alphabet_len(); - for b in 0..self.alphabet_len() { - self.trans.swap(o1 + b, o2 + b); - } - self.matches.swap(id1.to_usize(), id2.to_usize()); - } - - /// This routine shuffles all match states in this DFA to the beginning - /// of the DFA such that every non-match state appears after every match - /// state. (With one exception: the special fail and dead states remain as - /// the first two states.) - /// - /// The purpose of doing this shuffling is to avoid an extra conditional - /// in the search loop, and in particular, detecting whether a state is a - /// match or not does not need to access any memory. - /// - /// This updates `self.max_match` to point to the last matching state as - /// well as `self.start` if the starting state was moved. - fn shuffle_match_states(&mut self) { - assert!( - !self.premultiplied, - "cannot shuffle match states of premultiplied DFA" - ); - - if self.state_count <= 1 { - return; - } - - let mut first_non_match = self.start_id.to_usize(); - while first_non_match < self.state_count - && self.matches[first_non_match].len() > 0 - { - first_non_match += 1; - } - - let mut swaps: Vec = vec![fail_id(); self.state_count]; - let mut cur = self.state_count - 1; - while cur > first_non_match { - if self.matches[cur].len() > 0 { - self.swap_states( - S::from_usize(cur), - S::from_usize(first_non_match), - ); - swaps[cur] = S::from_usize(first_non_match); - swaps[first_non_match] = S::from_usize(cur); - - first_non_match += 1; - while first_non_match < cur - && self.matches[first_non_match].len() > 0 - { - first_non_match += 1; - } - } - cur -= 1; - } - for id in (0..self.state_count).map(S::from_usize) { - let alphabet_len = self.alphabet_len(); - let offset = id.to_usize() * alphabet_len; - for next in &mut self.trans[offset..offset + alphabet_len] { - if swaps[next.to_usize()] != fail_id() { - *next = swaps[next.to_usize()]; - } - } - } - if swaps[self.start_id.to_usize()] != fail_id() { - self.start_id = swaps[self.start_id.to_usize()]; - } - self.max_match = S::from_usize(first_non_match - 1); - } - - fn premultiply(&mut self) -> Result<()> { - if self.premultiplied || self.state_count <= 1 { - return Ok(()); - } - - let alpha_len = self.alphabet_len(); - premultiply_overflow_error( - S::from_usize(self.state_count - 1), - alpha_len, - )?; - - for id in (2..self.state_count).map(S::from_usize) { - let offset = id.to_usize() * alpha_len; - for next in &mut self.trans[offset..offset + alpha_len] { - if *next == dead_id() { - continue; - } - *next = S::from_usize(next.to_usize() * alpha_len); - } - } - self.premultiplied = true; - self.start_id = S::from_usize(self.start_id.to_usize() * alpha_len); - self.max_match = S::from_usize(self.max_match.to_usize() * alpha_len); - Ok(()) - } - - /// Computes the total amount of heap used by this NFA in bytes. - fn calculate_size(&mut self) { - let mut size = (self.trans.len() * size_of::()) - + (self.matches.len() - * size_of::>()); - for state_matches in &self.matches { - size += - state_matches.len() * size_of::<(PatternID, PatternLength)>(); - } - size += self.prefilter.as_ref().map_or(0, |p| p.as_ref().heap_bytes()); - self.heap_bytes = size; - } -} - -/// A builder for configuring the determinization of an NFA into a DFA. -#[derive(Clone, Debug)] -pub struct Builder { - premultiply: bool, - byte_classes: bool, -} - -impl Builder { - /// Create a new builder for a DFA. - pub fn new() -> Builder { - Builder { premultiply: true, byte_classes: true } - } - - /// Build a DFA from the given NFA. - /// - /// This returns an error if the state identifiers exceed their - /// representation size. This can only happen when state ids are - /// premultiplied (which is enabled by default). - pub fn build(&self, nfa: &NFA) -> Result> { - let byte_classes = if self.byte_classes { - nfa.byte_classes().clone() - } else { - ByteClasses::singletons() - }; - let alphabet_len = byte_classes.alphabet_len(); - let trans = vec![fail_id(); alphabet_len * nfa.state_len()]; - let matches = vec![vec![]; nfa.state_len()]; - let mut repr = Repr { - match_kind: nfa.match_kind().clone(), - anchored: nfa.anchored(), - premultiplied: false, - start_id: nfa.start_state(), - max_pattern_len: nfa.max_pattern_len(), - pattern_count: nfa.pattern_count(), - state_count: nfa.state_len(), - max_match: fail_id(), - heap_bytes: 0, - prefilter: nfa.prefilter_obj().map(|p| p.clone()), - byte_classes: byte_classes.clone(), - trans, - matches, - }; - for id in (0..nfa.state_len()).map(S::from_usize) { - repr.matches[id.to_usize()].extend_from_slice(nfa.matches(id)); - - let fail = nfa.failure_transition(id); - nfa.iter_all_transitions(&byte_classes, id, |b, mut next| { - if next == fail_id() { - next = nfa_next_state_memoized(nfa, &repr, id, fail, b); - } - repr.set_next_state(id, b, next); - }); - } - repr.shuffle_match_states(); - repr.calculate_size(); - if self.premultiply { - repr.premultiply()?; - if byte_classes.is_singleton() { - Ok(DFA::Premultiplied(Premultiplied(repr))) - } else { - Ok(DFA::PremultipliedByteClass(PremultipliedByteClass(repr))) - } - } else { - if byte_classes.is_singleton() { - Ok(DFA::Standard(Standard(repr))) - } else { - Ok(DFA::ByteClass(ByteClass(repr))) - } - } - } - - /// Whether to use byte classes or in the DFA. - pub fn byte_classes(&mut self, yes: bool) -> &mut Builder { - self.byte_classes = yes; - self - } - - /// Whether to premultiply state identifier in the DFA. - pub fn premultiply(&mut self, yes: bool) -> &mut Builder { - self.premultiply = yes; - self - } -} - -/// This returns the next NFA transition (including resolving failure -/// transitions), except once it sees a state id less than the id of the DFA -/// state that is currently being populated, then we no longer need to follow -/// failure transitions and can instead query the pre-computed state id from -/// the DFA itself. -/// -/// In general, this should only be called when a failure transition is seen. -fn nfa_next_state_memoized( - nfa: &NFA, - dfa: &Repr, - populating: S, - mut current: S, - input: u8, -) -> S { - loop { - if current < populating { - return dfa.next_state(current, input); - } - let next = nfa.next_state(current, input); - if next != fail_id() { - return next; - } - current = nfa.failure_transition(current); - } -} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/lib.rs b/third_party/cargo/vendor/aho-corasick-0.7.10/src/lib.rs deleted file mode 100644 index 28e984b..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/lib.rs +++ /dev/null @@ -1,297 +0,0 @@ -/*! -A library for finding occurrences of many patterns at once. This library -provides multiple pattern search principally through an implementation of the -[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm), -which builds a fast finite state machine for executing searches in linear time. - -Additionally, this library provides a number of configuration options for -building the automaton that permit controlling the space versus time trade -off. Other features include simple ASCII case insensitive matching, finding -overlapping matches, replacements, searching streams and even searching and -replacing text in streams. - -Finally, unlike all other (known) Aho-Corasick implementations, this one -supports enabling -[leftmost-first](enum.MatchKind.html#variant.LeftmostFirst) -or -[leftmost-longest](enum.MatchKind.html#variant.LeftmostFirst) -match semantics, using a (seemingly) novel alternative construction algorithm. -For more details on what match semantics means, see the -[`MatchKind`](enum.MatchKind.html) -type. - -# Overview - -This section gives a brief overview of the primary types in this crate: - -* [`AhoCorasick`](struct.AhoCorasick.html) is the primary type and represents - an Aho-Corasick automaton. This is the type you use to execute searches. -* [`AhoCorasickBuilder`](struct.AhoCorasickBuilder.html) can be used to build - an Aho-Corasick automaton, and supports configuring a number of options. -* [`Match`](struct.Match.html) represents a single match reported by an - Aho-Corasick automaton. Each match has two pieces of information: the pattern - that matched and the start and end byte offsets corresponding to the position - in the haystack at which it matched. - -Additionally, the [`packed`](packed/index.html) sub-module contains a lower -level API for using fast vectorized routines for finding a small number of -patterns in a haystack. - -# Example: basic searching - -This example shows how to search for occurrences of multiple patterns -simultaneously. Each match includes the pattern that matched along with the -byte offsets of the match. - -``` -use aho_corasick::AhoCorasick; - -let patterns = &["apple", "maple", "Snapple"]; -let haystack = "Nobody likes maple in their apple flavored Snapple."; - -let ac = AhoCorasick::new(patterns); -let mut matches = vec![]; -for mat in ac.find_iter(haystack) { - matches.push((mat.pattern(), mat.start(), mat.end())); -} -assert_eq!(matches, vec![ - (1, 13, 18), - (0, 28, 33), - (2, 43, 50), -]); -``` - -# Example: case insensitivity - -This is like the previous example, but matches `Snapple` case insensitively -using `AhoCorasickBuilder`: - -``` -use aho_corasick::AhoCorasickBuilder; - -let patterns = &["apple", "maple", "snapple"]; -let haystack = "Nobody likes maple in their apple flavored Snapple."; - -let ac = AhoCorasickBuilder::new() - .ascii_case_insensitive(true) - .build(patterns); -let mut matches = vec![]; -for mat in ac.find_iter(haystack) { - matches.push((mat.pattern(), mat.start(), mat.end())); -} -assert_eq!(matches, vec![ - (1, 13, 18), - (0, 28, 33), - (2, 43, 50), -]); -``` - -# Example: replacing matches in a stream - -This example shows how to execute a search and replace on a stream without -loading the entire stream into memory first. - -``` -use aho_corasick::AhoCorasick; - -# fn example() -> Result<(), ::std::io::Error> { -let patterns = &["fox", "brown", "quick"]; -let replace_with = &["sloth", "grey", "slow"]; - -// In a real example, these might be `std::fs::File`s instead. All you need to -// do is supply a pair of `std::io::Read` and `std::io::Write` implementations. -let rdr = "The quick brown fox."; -let mut wtr = vec![]; - -let ac = AhoCorasick::new(patterns); -ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)?; -assert_eq!(b"The slow grey sloth.".to_vec(), wtr); -# Ok(()) }; example().unwrap() -``` - -# Example: finding the leftmost first match - -In the textbook description of Aho-Corasick, its formulation is typically -structured such that it reports all possible matches, even when they overlap -with another. In many cases, overlapping matches may not be desired, such as -the case of finding all successive non-overlapping matches like you might with -a standard regular expression. - -Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do -this doesn't always work in the expected way, since it will report matches as -soon as they are seen. For example, consider matching the regex `Samwise|Sam` -against the text `Samwise`. Most regex engines (that are Perl-like, or -non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick -algorithm modified for reporting non-overlapping matches will report `Sam`. - -A novel contribution of this library is the ability to change the match -semantics of Aho-Corasick (without additional search time overhead) such that -`Samwise` is reported instead. For example, here's the standard approach: - -``` -use aho_corasick::AhoCorasick; - -let patterns = &["Samwise", "Sam"]; -let haystack = "Samwise"; - -let ac = AhoCorasick::new(patterns); -let mat = ac.find(haystack).expect("should have a match"); -assert_eq!("Sam", &haystack[mat.start()..mat.end()]); -``` - -And now here's the leftmost-first version, which matches how a Perl-like -regex will work: - -``` -use aho_corasick::{AhoCorasickBuilder, MatchKind}; - -let patterns = &["Samwise", "Sam"]; -let haystack = "Samwise"; - -let ac = AhoCorasickBuilder::new() - .match_kind(MatchKind::LeftmostFirst) - .build(patterns); -let mat = ac.find(haystack).expect("should have a match"); -assert_eq!("Samwise", &haystack[mat.start()..mat.end()]); -``` - -In addition to leftmost-first semantics, this library also supports -leftmost-longest semantics, which match the POSIX behavior of a regular -expression alternation. See -[`MatchKind`](enum.MatchKind.html) -for more details. - -# Prefilters - -While an Aho-Corasick automaton can perform admirably when compared to more -naive solutions, it is generally slower than more specialized algorithms that -are accelerated using vector instructions such as SIMD. - -For that reason, this library will internally use a "prefilter" to attempt -to accelerate searches when possible. Currently, this library has fairly -limited implementation that only applies when there are 3 or fewer unique -starting bytes among all patterns in an automaton. - -While a prefilter is generally good to have on by default since it works well -in the common case, it can lead to less predictable or even sub-optimal -performance in some cases. For that reason, prefilters can be disabled via -[`AhoCorasickBuilder::prefilter`](struct.AhoCorasickBuilder.html#method.prefilter). -*/ - -#![deny(missing_docs)] - -// We can never be truly no_std, but we could be alloc-only some day, so -// require the std feature for now. -#[cfg(not(feature = "std"))] -compile_error!("`std` feature is currently required to build this crate"); - -extern crate memchr; -#[cfg(test)] -#[macro_use] -extern crate doc_comment; - -#[cfg(test)] -doctest!("../README.md"); - -pub use ahocorasick::{ - AhoCorasick, AhoCorasickBuilder, FindIter, FindOverlappingIter, MatchKind, - StreamFindIter, -}; -pub use error::{Error, ErrorKind}; -pub use state_id::StateID; - -mod ahocorasick; -mod automaton; -mod buffer; -mod byte_frequencies; -mod classes; -mod dfa; -mod error; -mod nfa; -pub mod packed; -mod prefilter; -mod state_id; -#[cfg(test)] -mod tests; - -/// A representation of a match reported by an Aho-Corasick automaton. -/// -/// A match has two essential pieces of information: the identifier of the -/// pattern that matched, along with the start and end offsets of the match -/// in the haystack. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use aho_corasick::AhoCorasick; -/// -/// let ac = AhoCorasick::new(&[ -/// "foo", "bar", "baz", -/// ]); -/// let mat = ac.find("xxx bar xxx").expect("should have a match"); -/// assert_eq!(1, mat.pattern()); -/// assert_eq!(4, mat.start()); -/// assert_eq!(7, mat.end()); -/// ``` -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Match { - /// The pattern id. - pattern: usize, - /// The length of this match, such that the starting position of the match - /// is `end - len`. - /// - /// We use length here because, other than the pattern id, the only - /// information about each pattern that the automaton stores is its length. - /// So using the length here is just a bit more natural. But it isn't - /// technically required. - len: usize, - /// The end offset of the match, exclusive. - end: usize, -} - -impl Match { - /// Returns the identifier of the pattern that matched. - /// - /// The identifier of a pattern is derived from the position in which it - /// was originally inserted into the corresponding automaton. The first - /// pattern has identifier `0`, and each subsequent pattern is `1`, `2` - /// and so on. - #[inline] - pub fn pattern(&self) -> usize { - self.pattern - } - - /// The starting position of the match. - #[inline] - pub fn start(&self) -> usize { - self.end - self.len - } - - /// The ending position of the match. - #[inline] - pub fn end(&self) -> usize { - self.end - } - - /// Returns true if and only if this match is empty. That is, when - /// `start() == end()`. - /// - /// An empty match can only be returned when the empty string was among - /// the patterns used to build the Aho-Corasick automaton. - #[inline] - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - #[inline] - fn increment(&self, by: usize) -> Match { - Match { pattern: self.pattern, len: self.len, end: self.end + by } - } - - #[inline] - fn from_span(id: usize, start: usize, end: usize) -> Match { - Match { pattern: id, len: end - start, end } - } -} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/tests.rs b/third_party/cargo/vendor/aho-corasick-0.7.10/src/tests.rs deleted file mode 100644 index 0ae31f0..0000000 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/tests.rs +++ /dev/null @@ -1,1152 +0,0 @@ -use std::collections::HashMap; -use std::io; -use std::usize; - -use {AhoCorasickBuilder, Match, MatchKind}; - -/// A description of a single test against an Aho-Corasick automaton. -/// -/// A single test may not necessarily pass on every configuration of an -/// Aho-Corasick automaton. The tests are categorized and grouped appropriately -/// below. -#[derive(Clone, Debug, Eq, PartialEq)] -struct SearchTest { - /// The name of this test, for debugging. - name: &'static str, - /// The patterns to search for. - patterns: &'static [&'static str], - /// The text to search. - haystack: &'static str, - /// Each match is a triple of (pattern_index, start, end), where - /// pattern_index is an index into `patterns` and `start`/`end` are indices - /// into `haystack`. - matches: &'static [(usize, usize, usize)], -} - -/// Short-hand constructor for SearchTest. We use it a lot below. -macro_rules! t { - ($name:ident, $patterns:expr, $haystack:expr, $matches:expr) => { - SearchTest { - name: stringify!($name), - patterns: $patterns, - haystack: $haystack, - matches: $matches, - } - }; -} - -/// A collection of test groups. -type TestCollection = &'static [&'static [SearchTest]]; - -// Define several collections corresponding to the different type of match -// semantics supported by Aho-Corasick. These collections have some overlap, -// but each collection should have some tests that no other collection has. - -/// Tests for Aho-Corasick's standard non-overlapping match semantics. -const AC_STANDARD_NON_OVERLAPPING: TestCollection = - &[BASICS, NON_OVERLAPPING, STANDARD, REGRESSION]; - -/// Tests for Aho-Corasick's anchored standard non-overlapping match semantics. -const AC_STANDARD_ANCHORED_NON_OVERLAPPING: TestCollection = - &[ANCHORED_BASICS, ANCHORED_NON_OVERLAPPING, STANDARD_ANCHORED]; - -/// Tests for Aho-Corasick's standard overlapping match semantics. -const AC_STANDARD_OVERLAPPING: TestCollection = - &[BASICS, OVERLAPPING, REGRESSION]; - -/// Tests for Aho-Corasick's anchored standard overlapping match semantics. -const AC_STANDARD_ANCHORED_OVERLAPPING: TestCollection = - &[ANCHORED_BASICS, ANCHORED_OVERLAPPING]; - -/// Tests for Aho-Corasick's leftmost-first match semantics. -const AC_LEFTMOST_FIRST: TestCollection = - &[BASICS, NON_OVERLAPPING, LEFTMOST, LEFTMOST_FIRST, REGRESSION]; - -/// Tests for Aho-Corasick's anchored leftmost-first match semantics. -const AC_LEFTMOST_FIRST_ANCHORED: TestCollection = &[ - ANCHORED_BASICS, - ANCHORED_NON_OVERLAPPING, - ANCHORED_LEFTMOST, - ANCHORED_LEFTMOST_FIRST, -]; - -/// Tests for Aho-Corasick's leftmost-longest match semantics. -const AC_LEFTMOST_LONGEST: TestCollection = - &[BASICS, NON_OVERLAPPING, LEFTMOST, LEFTMOST_LONGEST, REGRESSION]; - -/// Tests for Aho-Corasick's anchored leftmost-longest match semantics. -const AC_LEFTMOST_LONGEST_ANCHORED: TestCollection = &[ - ANCHORED_BASICS, - ANCHORED_NON_OVERLAPPING, - ANCHORED_LEFTMOST, - ANCHORED_LEFTMOST_LONGEST, -]; - -// Now define the individual tests that make up the collections above. - -/// A collection of tests for the Aho-Corasick algorithm that should always be -/// true regardless of match semantics. That is, all combinations of -/// leftmost-{shortest, first, longest} x {overlapping, non-overlapping} -/// should produce the same answer. -const BASICS: &'static [SearchTest] = &[ - t!(basic000, &[], "", &[]), - t!(basic001, &["a"], "", &[]), - t!(basic010, &["a"], "a", &[(0, 0, 1)]), - t!(basic020, &["a"], "aa", &[(0, 0, 1), (0, 1, 2)]), - t!(basic030, &["a"], "aaa", &[(0, 0, 1), (0, 1, 2), (0, 2, 3)]), - t!(basic040, &["a"], "aba", &[(0, 0, 1), (0, 2, 3)]), - t!(basic050, &["a"], "bba", &[(0, 2, 3)]), - t!(basic060, &["a"], "bbb", &[]), - t!(basic070, &["a"], "bababbbba", &[(0, 1, 2), (0, 3, 4), (0, 8, 9)]), - t!(basic100, &["aa"], "", &[]), - t!(basic110, &["aa"], "aa", &[(0, 0, 2)]), - t!(basic120, &["aa"], "aabbaa", &[(0, 0, 2), (0, 4, 6)]), - t!(basic130, &["aa"], "abbab", &[]), - t!(basic140, &["aa"], "abbabaa", &[(0, 5, 7)]), - t!(basic200, &["abc"], "abc", &[(0, 0, 3)]), - t!(basic210, &["abc"], "zazabzabcz", &[(0, 6, 9)]), - t!(basic220, &["abc"], "zazabczabcz", &[(0, 3, 6), (0, 7, 10)]), - t!(basic300, &["a", "b"], "", &[]), - t!(basic310, &["a", "b"], "z", &[]), - t!(basic320, &["a", "b"], "b", &[(1, 0, 1)]), - t!(basic330, &["a", "b"], "a", &[(0, 0, 1)]), - t!( - basic340, - &["a", "b"], - "abba", - &[(0, 0, 1), (1, 1, 2), (1, 2, 3), (0, 3, 4),] - ), - t!( - basic350, - &["b", "a"], - "abba", - &[(1, 0, 1), (0, 1, 2), (0, 2, 3), (1, 3, 4),] - ), - t!(basic360, &["abc", "bc"], "xbc", &[(1, 1, 3),]), - t!(basic400, &["foo", "bar"], "", &[]), - t!(basic410, &["foo", "bar"], "foobar", &[(0, 0, 3), (1, 3, 6),]), - t!(basic420, &["foo", "bar"], "barfoo", &[(1, 0, 3), (0, 3, 6),]), - t!(basic430, &["foo", "bar"], "foofoo", &[(0, 0, 3), (0, 3, 6),]), - t!(basic440, &["foo", "bar"], "barbar", &[(1, 0, 3), (1, 3, 6),]), - t!(basic450, &["foo", "bar"], "bafofoo", &[(0, 4, 7),]), - t!(basic460, &["bar", "foo"], "bafofoo", &[(1, 4, 7),]), - t!(basic470, &["foo", "bar"], "fobabar", &[(1, 4, 7),]), - t!(basic480, &["bar", "foo"], "fobabar", &[(0, 4, 7),]), - t!(basic600, &[""], "", &[(0, 0, 0)]), - t!(basic610, &[""], "a", &[(0, 0, 0), (0, 1, 1)]), - t!(basic620, &[""], "abc", &[(0, 0, 0), (0, 1, 1), (0, 2, 2), (0, 3, 3)]), - t!(basic700, &["yabcdef", "abcdezghi"], "yabcdefghi", &[(0, 0, 7),]), - t!(basic710, &["yabcdef", "abcdezghi"], "yabcdezghi", &[(1, 1, 10),]), - t!( - basic720, - &["yabcdef", "bcdeyabc", "abcdezghi"], - "yabcdezghi", - &[(2, 1, 10),] - ), -]; - -/// A collection of *anchored* tests for the Aho-Corasick algorithm that should -/// always be true regardless of match semantics. That is, all combinations of -/// leftmost-{shortest, first, longest} x {overlapping, non-overlapping} should -/// produce the same answer. -const ANCHORED_BASICS: &'static [SearchTest] = &[ - t!(abasic000, &[], "", &[]), - t!(abasic010, &[""], "", &[(0, 0, 0)]), - t!(abasic020, &[""], "a", &[(0, 0, 0)]), - t!(abasic030, &[""], "abc", &[(0, 0, 0)]), - t!(abasic100, &["a"], "a", &[(0, 0, 1)]), - t!(abasic110, &["a"], "aa", &[(0, 0, 1)]), - t!(abasic120, &["a", "b"], "ab", &[(0, 0, 1)]), - t!(abasic130, &["a", "b"], "ba", &[(1, 0, 1)]), - t!(abasic140, &["foo", "foofoo"], "foo", &[(0, 0, 3)]), - t!(abasic150, &["foofoo", "foo"], "foo", &[(1, 0, 3)]), -]; - -/// Tests for non-overlapping standard match semantics. -/// -/// These tests generally shouldn't pass for leftmost-{first,longest}, although -/// some do in order to write clearer tests. For example, standard000 will -/// pass with leftmost-first semantics, but standard010 will not. We write -/// both to emphasize how the match semantics work. -const STANDARD: &'static [SearchTest] = &[ - t!(standard000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), - t!(standard010, &["abcd", "ab"], "abcd", &[(1, 0, 2)]), - t!(standard020, &["abcd", "ab", "abc"], "abcd", &[(1, 0, 2)]), - t!(standard030, &["abcd", "abc", "ab"], "abcd", &[(2, 0, 2)]), - t!(standard040, &["a", ""], "a", &[(1, 0, 0), (1, 1, 1)]), - t!( - standard400, - &["abcd", "bcd", "cd", "b"], - "abcd", - &[(3, 1, 2), (2, 2, 4),] - ), - t!(standard410, &["", "a"], "a", &[(0, 0, 0), (0, 1, 1),]), - t!(standard420, &["", "a"], "aa", &[(0, 0, 0), (0, 1, 1), (0, 2, 2),]), - t!(standard430, &["", "a", ""], "a", &[(0, 0, 0), (0, 1, 1),]), - t!(standard440, &["a", "", ""], "a", &[(1, 0, 0), (1, 1, 1),]), - t!(standard450, &["", "", "a"], "a", &[(0, 0, 0), (0, 1, 1),]), -]; - -/// Like STANDARD, but for anchored searches. -const STANDARD_ANCHORED: &'static [SearchTest] = &[ - t!(astandard000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), - t!(astandard010, &["abcd", "ab"], "abcd", &[(1, 0, 2)]), - t!(astandard020, &["abcd", "ab", "abc"], "abcd", &[(1, 0, 2)]), - t!(astandard030, &["abcd", "abc", "ab"], "abcd", &[(2, 0, 2)]), - t!(astandard040, &["a", ""], "a", &[(1, 0, 0)]), - t!(astandard050, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4)]), - t!(astandard410, &["", "a"], "a", &[(0, 0, 0)]), - t!(astandard420, &["", "a"], "aa", &[(0, 0, 0)]), - t!(astandard430, &["", "a", ""], "a", &[(0, 0, 0)]), - t!(astandard440, &["a", "", ""], "a", &[(1, 0, 0)]), - t!(astandard450, &["", "", "a"], "a", &[(0, 0, 0)]), -]; - -/// Tests for non-overlapping leftmost match semantics. These should pass for -/// both leftmost-first and leftmost-longest match kinds. Stated differently, -/// among ambiguous matches, the longest match and the match that appeared -/// first when constructing the automaton should always be the same. -const LEFTMOST: &'static [SearchTest] = &[ - t!(leftmost000, &["ab", "ab"], "abcd", &[(0, 0, 2)]), - t!(leftmost010, &["a", ""], "a", &[(0, 0, 1), (1, 1, 1)]), - t!(leftmost020, &["", ""], "a", &[(0, 0, 0), (0, 1, 1)]), - t!(leftmost030, &["a", "ab"], "aa", &[(0, 0, 1), (0, 1, 2)]), - t!(leftmost031, &["ab", "a"], "aa", &[(1, 0, 1), (1, 1, 2)]), - t!(leftmost032, &["ab", "a"], "xayabbbz", &[(1, 1, 2), (0, 3, 5)]), - t!(leftmost300, &["abcd", "bce", "b"], "abce", &[(1, 1, 4)]), - t!(leftmost310, &["abcd", "ce", "bc"], "abce", &[(2, 1, 3)]), - t!(leftmost320, &["abcd", "bce", "ce", "b"], "abce", &[(1, 1, 4)]), - t!(leftmost330, &["abcd", "bce", "cz", "bc"], "abcz", &[(3, 1, 3)]), - t!(leftmost340, &["bce", "cz", "bc"], "bcz", &[(2, 0, 2)]), - t!(leftmost350, &["abc", "bd", "ab"], "abd", &[(2, 0, 2)]), - t!( - leftmost360, - &["abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(2, 0, 8),] - ), - t!( - leftmost370, - &["abcdefghi", "cde", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!( - leftmost380, - &["abcdefghi", "hz", "abcdefgh", "a"], - "abcdefghz", - &[(2, 0, 8),] - ), - t!( - leftmost390, - &["b", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!( - leftmost400, - &["h", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!( - leftmost410, - &["z", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8), (0, 8, 9),] - ), -]; - -/// Like LEFTMOST, but for anchored searches. -const ANCHORED_LEFTMOST: &'static [SearchTest] = &[ - t!(aleftmost000, &["ab", "ab"], "abcd", &[(0, 0, 2)]), - t!(aleftmost010, &["a", ""], "a", &[(0, 0, 1)]), - t!(aleftmost020, &["", ""], "a", &[(0, 0, 0)]), - t!(aleftmost030, &["a", "ab"], "aa", &[(0, 0, 1)]), - t!(aleftmost031, &["ab", "a"], "aa", &[(1, 0, 1)]), - t!(aleftmost032, &["ab", "a"], "xayabbbz", &[]), - t!(aleftmost300, &["abcd", "bce", "b"], "abce", &[]), - t!(aleftmost310, &["abcd", "ce", "bc"], "abce", &[]), - t!(aleftmost320, &["abcd", "bce", "ce", "b"], "abce", &[]), - t!(aleftmost330, &["abcd", "bce", "cz", "bc"], "abcz", &[]), - t!(aleftmost340, &["bce", "cz", "bc"], "bcz", &[(2, 0, 2)]), - t!(aleftmost350, &["abc", "bd", "ab"], "abd", &[(2, 0, 2)]), - t!( - aleftmost360, - &["abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(2, 0, 8),] - ), - t!( - aleftmost370, - &["abcdefghi", "cde", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!( - aleftmost380, - &["abcdefghi", "hz", "abcdefgh", "a"], - "abcdefghz", - &[(2, 0, 8),] - ), - t!( - aleftmost390, - &["b", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!( - aleftmost400, - &["h", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!( - aleftmost410, - &["z", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8)] - ), -]; - -/// Tests for non-overlapping leftmost-first match semantics. These tests -/// should generally be specific to leftmost-first, which means they should -/// generally fail under leftmost-longest semantics. -const LEFTMOST_FIRST: &'static [SearchTest] = &[ - t!(leftfirst000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), - t!(leftfirst010, &["", "a"], "a", &[(0, 0, 0), (0, 1, 1)]), - t!(leftfirst011, &["", "a", ""], "a", &[(0, 0, 0), (0, 1, 1),]), - t!(leftfirst012, &["a", "", ""], "a", &[(0, 0, 1), (1, 1, 1),]), - t!(leftfirst013, &["", "", "a"], "a", &[(0, 0, 0), (0, 1, 1),]), - t!(leftfirst020, &["abcd", "ab"], "abcd", &[(0, 0, 4)]), - t!(leftfirst030, &["ab", "ab"], "abcd", &[(0, 0, 2)]), - t!(leftfirst040, &["a", "ab"], "xayabbbz", &[(0, 1, 2), (0, 3, 4)]), - t!(leftfirst100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[(1, 1, 5)]), - t!(leftfirst110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[(1, 1, 6)]), - t!(leftfirst300, &["abcd", "b", "bce"], "abce", &[(1, 1, 2)]), - t!( - leftfirst310, - &["abcd", "b", "bce", "ce"], - "abce", - &[(1, 1, 2), (3, 2, 4),] - ), - t!( - leftfirst320, - &["a", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(0, 0, 1), (2, 7, 9),] - ), - t!(leftfirst330, &["a", "abab"], "abab", &[(0, 0, 1), (0, 2, 3)]), -]; - -/// Like LEFTMOST_FIRST, but for anchored searches. -const ANCHORED_LEFTMOST_FIRST: &'static [SearchTest] = &[ - t!(aleftfirst000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), - t!(aleftfirst010, &["", "a"], "a", &[(0, 0, 0)]), - t!(aleftfirst011, &["", "a", ""], "a", &[(0, 0, 0)]), - t!(aleftfirst012, &["a", "", ""], "a", &[(0, 0, 1)]), - t!(aleftfirst013, &["", "", "a"], "a", &[(0, 0, 0)]), - t!(aleftfirst020, &["abcd", "ab"], "abcd", &[(0, 0, 4)]), - t!(aleftfirst030, &["ab", "ab"], "abcd", &[(0, 0, 2)]), - t!(aleftfirst040, &["a", "ab"], "xayabbbz", &[]), - t!(aleftfirst100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[]), - t!(aleftfirst110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[]), - t!(aleftfirst300, &["abcd", "b", "bce"], "abce", &[]), - t!(aleftfirst310, &["abcd", "b", "bce", "ce"], "abce", &[]), - t!( - aleftfirst320, - &["a", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(0, 0, 1)] - ), - t!(aleftfirst330, &["a", "abab"], "abab", &[(0, 0, 1)]), -]; - -/// Tests for non-overlapping leftmost-longest match semantics. These tests -/// should generally be specific to leftmost-longest, which means they should -/// generally fail under leftmost-first semantics. -const LEFTMOST_LONGEST: &'static [SearchTest] = &[ - t!(leftlong000, &["ab", "abcd"], "abcd", &[(1, 0, 4)]), - t!(leftlong010, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4),]), - t!(leftlong020, &["", "a"], "a", &[(1, 0, 1), (0, 1, 1),]), - t!(leftlong021, &["", "a", ""], "a", &[(1, 0, 1), (0, 1, 1),]), - t!(leftlong022, &["a", "", ""], "a", &[(0, 0, 1), (1, 1, 1),]), - t!(leftlong023, &["", "", "a"], "a", &[(2, 0, 1), (0, 1, 1),]), - t!(leftlong030, &["", "a"], "aa", &[(1, 0, 1), (1, 1, 2), (0, 2, 2),]), - t!(leftlong040, &["a", "ab"], "a", &[(0, 0, 1)]), - t!(leftlong050, &["a", "ab"], "ab", &[(1, 0, 2)]), - t!(leftlong060, &["ab", "a"], "a", &[(1, 0, 1)]), - t!(leftlong070, &["ab", "a"], "ab", &[(0, 0, 2)]), - t!(leftlong100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[(2, 1, 6)]), - t!(leftlong110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[(1, 1, 6)]), - t!(leftlong300, &["abcd", "b", "bce"], "abce", &[(2, 1, 4)]), - t!( - leftlong310, - &["a", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!(leftlong320, &["a", "abab"], "abab", &[(1, 0, 4)]), - t!(leftlong330, &["abcd", "b", "ce"], "abce", &[(1, 1, 2), (2, 2, 4),]), - t!(leftlong340, &["a", "ab"], "xayabbbz", &[(0, 1, 2), (1, 3, 5)]), -]; - -/// Like LEFTMOST_LONGEST, but for anchored searches. -const ANCHORED_LEFTMOST_LONGEST: &'static [SearchTest] = &[ - t!(aleftlong000, &["ab", "abcd"], "abcd", &[(1, 0, 4)]), - t!(aleftlong010, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4),]), - t!(aleftlong020, &["", "a"], "a", &[(1, 0, 1)]), - t!(aleftlong021, &["", "a", ""], "a", &[(1, 0, 1)]), - t!(aleftlong022, &["a", "", ""], "a", &[(0, 0, 1)]), - t!(aleftlong023, &["", "", "a"], "a", &[(2, 0, 1)]), - t!(aleftlong030, &["", "a"], "aa", &[(1, 0, 1)]), - t!(aleftlong040, &["a", "ab"], "a", &[(0, 0, 1)]), - t!(aleftlong050, &["a", "ab"], "ab", &[(1, 0, 2)]), - t!(aleftlong060, &["ab", "a"], "a", &[(1, 0, 1)]), - t!(aleftlong070, &["ab", "a"], "ab", &[(0, 0, 2)]), - t!(aleftlong100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[]), - t!(aleftlong110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[]), - t!(aleftlong300, &["abcd", "b", "bce"], "abce", &[]), - t!( - aleftlong310, - &["a", "abcdefghi", "hz", "abcdefgh"], - "abcdefghz", - &[(3, 0, 8),] - ), - t!(aleftlong320, &["a", "abab"], "abab", &[(1, 0, 4)]), - t!(aleftlong330, &["abcd", "b", "ce"], "abce", &[]), - t!(aleftlong340, &["a", "ab"], "xayabbbz", &[]), -]; - -/// Tests for non-overlapping match semantics. -/// -/// Generally these tests shouldn't pass when using overlapping semantics. -/// These should pass for both standard and leftmost match semantics. -const NON_OVERLAPPING: &'static [SearchTest] = &[ - t!(nover010, &["abcd", "bcd", "cd"], "abcd", &[(0, 0, 4),]), - t!(nover020, &["bcd", "cd", "abcd"], "abcd", &[(2, 0, 4),]), - t!(nover030, &["abc", "bc"], "zazabcz", &[(0, 3, 6),]), - t!( - nover100, - &["ab", "ba"], - "abababa", - &[(0, 0, 2), (0, 2, 4), (0, 4, 6),] - ), - t!(nover200, &["foo", "foo"], "foobarfoo", &[(0, 0, 3), (0, 6, 9),]), - t!(nover300, &["", ""], "", &[(0, 0, 0),]), - t!(nover310, &["", ""], "a", &[(0, 0, 0), (0, 1, 1),]), -]; - -/// Like NON_OVERLAPPING, but for anchored searches. -const ANCHORED_NON_OVERLAPPING: &'static [SearchTest] = &[ - t!(anover010, &["abcd", "bcd", "cd"], "abcd", &[(0, 0, 4),]), - t!(anover020, &["bcd", "cd", "abcd"], "abcd", &[(2, 0, 4),]), - t!(anover030, &["abc", "bc"], "zazabcz", &[]), - t!(anover100, &["ab", "ba"], "abababa", &[(0, 0, 2)]), - t!(anover200, &["foo", "foo"], "foobarfoo", &[(0, 0, 3)]), - t!(anover300, &["", ""], "", &[(0, 0, 0),]), - t!(anover310, &["", ""], "a", &[(0, 0, 0)]), -]; - -/// Tests for overlapping match semantics. -/// -/// This only supports standard match semantics, since leftmost-{first,longest} -/// do not support overlapping matches. -const OVERLAPPING: &'static [SearchTest] = &[ - t!( - over000, - &["abcd", "bcd", "cd", "b"], - "abcd", - &[(3, 1, 2), (0, 0, 4), (1, 1, 4), (2, 2, 4),] - ), - t!( - over010, - &["bcd", "cd", "b", "abcd"], - "abcd", - &[(2, 1, 2), (3, 0, 4), (0, 1, 4), (1, 2, 4),] - ), - t!( - over020, - &["abcd", "bcd", "cd"], - "abcd", - &[(0, 0, 4), (1, 1, 4), (2, 2, 4),] - ), - t!( - over030, - &["bcd", "abcd", "cd"], - "abcd", - &[(1, 0, 4), (0, 1, 4), (2, 2, 4),] - ), - t!( - over040, - &["bcd", "cd", "abcd"], - "abcd", - &[(2, 0, 4), (0, 1, 4), (1, 2, 4),] - ), - t!(over050, &["abc", "bc"], "zazabcz", &[(0, 3, 6), (1, 4, 6),]), - t!( - over100, - &["ab", "ba"], - "abababa", - &[(0, 0, 2), (1, 1, 3), (0, 2, 4), (1, 3, 5), (0, 4, 6), (1, 5, 7),] - ), - t!( - over200, - &["foo", "foo"], - "foobarfoo", - &[(0, 0, 3), (1, 0, 3), (0, 6, 9), (1, 6, 9),] - ), - t!(over300, &["", ""], "", &[(0, 0, 0), (1, 0, 0),]), - t!( - over310, - &["", ""], - "a", - &[(0, 0, 0), (1, 0, 0), (0, 1, 1), (1, 1, 1),] - ), - t!(over320, &["", "a"], "a", &[(0, 0, 0), (1, 0, 1), (0, 1, 1),]), - t!( - over330, - &["", "a", ""], - "a", - &[(0, 0, 0), (2, 0, 0), (1, 0, 1), (0, 1, 1), (2, 1, 1),] - ), - t!( - over340, - &["a", "", ""], - "a", - &[(1, 0, 0), (2, 0, 0), (0, 0, 1), (1, 1, 1), (2, 1, 1),] - ), - t!( - over350, - &["", "", "a"], - "a", - &[(0, 0, 0), (1, 0, 0), (2, 0, 1), (0, 1, 1), (1, 1, 1),] - ), - t!( - over360, - &["foo", "foofoo"], - "foofoo", - &[(0, 0, 3), (1, 0, 6), (0, 3, 6)] - ), -]; - -/// Like OVERLAPPING, but for anchored searches. -const ANCHORED_OVERLAPPING: &'static [SearchTest] = &[ - t!(aover000, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4)]), - t!(aover010, &["bcd", "cd", "b", "abcd"], "abcd", &[(3, 0, 4)]), - t!(aover020, &["abcd", "bcd", "cd"], "abcd", &[(0, 0, 4)]), - t!(aover030, &["bcd", "abcd", "cd"], "abcd", &[(1, 0, 4)]), - t!(aover040, &["bcd", "cd", "abcd"], "abcd", &[(2, 0, 4)]), - t!(aover050, &["abc", "bc"], "zazabcz", &[]), - t!(aover100, &["ab", "ba"], "abababa", &[(0, 0, 2)]), - t!(aover200, &["foo", "foo"], "foobarfoo", &[(0, 0, 3), (1, 0, 3)]), - t!(aover300, &["", ""], "", &[(0, 0, 0), (1, 0, 0),]), - t!(aover310, &["", ""], "a", &[(0, 0, 0), (1, 0, 0)]), - t!(aover320, &["", "a"], "a", &[(0, 0, 0), (1, 0, 1)]), - t!(aover330, &["", "a", ""], "a", &[(0, 0, 0), (2, 0, 0), (1, 0, 1)]), - t!(aover340, &["a", "", ""], "a", &[(1, 0, 0), (2, 0, 0), (0, 0, 1)]), - t!(aover350, &["", "", "a"], "a", &[(0, 0, 0), (1, 0, 0), (2, 0, 1)]), - t!(aover360, &["foo", "foofoo"], "foofoo", &[(0, 0, 3), (1, 0, 6)]), -]; - -/// Tests for ASCII case insensitivity. -/// -/// These tests should all have the same behavior regardless of match semantics -/// or whether the search is overlapping. -const ASCII_CASE_INSENSITIVE: &'static [SearchTest] = &[ - t!(acasei000, &["a"], "A", &[(0, 0, 1)]), - t!(acasei010, &["Samwise"], "SAMWISE", &[(0, 0, 7)]), - t!(acasei011, &["Samwise"], "SAMWISE.abcd", &[(0, 0, 7)]), - t!(acasei020, &["fOoBaR"], "quux foobar baz", &[(0, 5, 11)]), -]; - -/// Like ASCII_CASE_INSENSITIVE, but specifically for non-overlapping tests. -const ASCII_CASE_INSENSITIVE_NON_OVERLAPPING: &'static [SearchTest] = &[ - t!(acasei000, &["foo", "FOO"], "fOo", &[(0, 0, 3)]), - t!(acasei000, &["FOO", "foo"], "fOo", &[(0, 0, 3)]), -]; - -/// Like ASCII_CASE_INSENSITIVE, but specifically for overlapping tests. -const ASCII_CASE_INSENSITIVE_OVERLAPPING: &'static [SearchTest] = &[ - t!(acasei000, &["foo", "FOO"], "fOo", &[(0, 0, 3), (1, 0, 3)]), - t!(acasei001, &["FOO", "foo"], "fOo", &[(0, 0, 3), (1, 0, 3)]), -]; - -/// Regression tests that are applied to all Aho-Corasick combinations. -/// -/// If regression tests are needed for specific match semantics, then add them -/// to the appropriate group above. -const REGRESSION: &'static [SearchTest] = &[ - t!(regression010, &["inf", "ind"], "infind", &[(0, 0, 3), (1, 3, 6),]), - t!(regression020, &["ind", "inf"], "infind", &[(1, 0, 3), (0, 3, 6),]), - t!( - regression030, - &["libcore/", "libstd/"], - "libcore/char/methods.rs", - &[(0, 0, 8),] - ), - t!( - regression040, - &["libstd/", "libcore/"], - "libcore/char/methods.rs", - &[(1, 0, 8),] - ), - t!( - regression050, - &["\x00\x00\x01", "\x00\x00\x00"], - "\x00\x00\x00", - &[(1, 0, 3),] - ), - t!( - regression060, - &["\x00\x00\x00", "\x00\x00\x01"], - "\x00\x00\x00", - &[(0, 0, 3),] - ), -]; - -// Now define a test for each combination of things above that we want to run. -// Since there are a few different combinations for each collection of tests, -// we define a couple of macros to avoid repetition drudgery. The testconfig -// macro constructs the automaton from a given match kind, and runs the search -// tests one-by-one over the given collection. The `with` parameter allows one -// to configure the builder with additional parameters. The testcombo macro -// invokes testconfig in precisely this way: it sets up several tests where -// each one turns a different knob on AhoCorasickBuilder. - -macro_rules! testconfig { - (overlapping, $name:ident, $collection:expr, $kind:ident, $with:expr) => { - #[test] - fn $name() { - run_search_tests($collection, |test| { - let mut builder = AhoCorasickBuilder::new(); - $with(&mut builder); - builder - .match_kind(MatchKind::$kind) - .build(test.patterns) - .find_overlapping_iter(test.haystack) - .collect() - }); - } - }; - (stream, $name:ident, $collection:expr, $kind:ident, $with:expr) => { - #[test] - fn $name() { - run_search_tests($collection, |test| { - let buf = - io::BufReader::with_capacity(1, test.haystack.as_bytes()); - let mut builder = AhoCorasickBuilder::new(); - $with(&mut builder); - builder - .match_kind(MatchKind::$kind) - .build(test.patterns) - .stream_find_iter(buf) - .map(|result| result.unwrap()) - .collect() - }); - } - }; - ($name:ident, $collection:expr, $kind:ident, $with:expr) => { - #[test] - fn $name() { - run_search_tests($collection, |test| { - let mut builder = AhoCorasickBuilder::new(); - $with(&mut builder); - builder - .match_kind(MatchKind::$kind) - .build(test.patterns) - .find_iter(test.haystack) - .collect() - }); - } - }; -} - -macro_rules! testcombo { - ($name:ident, $collection:expr, $kind:ident) => { - mod $name { - use super::*; - - testconfig!(nfa_default, $collection, $kind, |_| ()); - testconfig!( - nfa_no_prefilter, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.prefilter(false); - } - ); - testconfig!( - nfa_all_sparse, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dense_depth(0); - } - ); - testconfig!( - nfa_all_dense, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dense_depth(usize::MAX); - } - ); - testconfig!( - dfa_default, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true); - } - ); - testconfig!( - dfa_no_prefilter, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).prefilter(false); - } - ); - testconfig!( - dfa_all_sparse, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).dense_depth(0); - } - ); - testconfig!( - dfa_all_dense, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).dense_depth(usize::MAX); - } - ); - testconfig!( - dfa_no_byte_class, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).byte_classes(false); - } - ); - testconfig!( - dfa_no_premultiply, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).premultiply(false); - } - ); - testconfig!( - dfa_no_byte_class_no_premultiply, - $collection, - $kind, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).byte_classes(false).premultiply(false); - } - ); - } - }; -} - -// Write out the combinations. -testcombo!(search_leftmost_longest, AC_LEFTMOST_LONGEST, LeftmostLongest); -testcombo!(search_leftmost_first, AC_LEFTMOST_FIRST, LeftmostFirst); -testcombo!( - search_standard_nonoverlapping, - AC_STANDARD_NON_OVERLAPPING, - Standard -); - -// Write out the overlapping combo by hand since there is only one of them. -testconfig!( - overlapping, - search_standard_overlapping_nfa_default, - AC_STANDARD_OVERLAPPING, - Standard, - |_| () -); -testconfig!( - overlapping, - search_standard_overlapping_nfa_all_sparse, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dense_depth(0); - } -); -testconfig!( - overlapping, - search_standard_overlapping_nfa_all_dense, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dense_depth(usize::MAX); - } -); -testconfig!( - overlapping, - search_standard_overlapping_dfa_default, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true); - } -); -testconfig!( - overlapping, - search_standard_overlapping_dfa_all_sparse, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).dense_depth(0); - } -); -testconfig!( - overlapping, - search_standard_overlapping_dfa_all_dense, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).dense_depth(usize::MAX); - } -); -testconfig!( - overlapping, - search_standard_overlapping_dfa_no_byte_class, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).byte_classes(false); - } -); -testconfig!( - overlapping, - search_standard_overlapping_dfa_no_premultiply, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).premultiply(false); - } -); -testconfig!( - overlapping, - search_standard_overlapping_dfa_no_byte_class_no_premultiply, - AC_STANDARD_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true).byte_classes(false).premultiply(false); - } -); - -// Also write out tests manually for streams, since we only test the standard -// match semantics. We also don't bother testing different automaton -// configurations, since those are well covered by tests above. -testconfig!( - stream, - search_standard_stream_nfa_default, - AC_STANDARD_NON_OVERLAPPING, - Standard, - |_| () -); -testconfig!( - stream, - search_standard_stream_dfa_default, - AC_STANDARD_NON_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.dfa(true); - } -); - -// Same thing for anchored searches. Write them out manually. -testconfig!( - search_standard_anchored_nfa_default, - AC_STANDARD_ANCHORED_NON_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.anchored(true); - } -); -testconfig!( - search_standard_anchored_dfa_default, - AC_STANDARD_ANCHORED_NON_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.anchored(true).dfa(true); - } -); -testconfig!( - overlapping, - search_standard_anchored_overlapping_nfa_default, - AC_STANDARD_ANCHORED_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.anchored(true); - } -); -testconfig!( - overlapping, - search_standard_anchored_overlapping_dfa_default, - AC_STANDARD_ANCHORED_OVERLAPPING, - Standard, - |b: &mut AhoCorasickBuilder| { - b.anchored(true).dfa(true); - } -); -testconfig!( - search_leftmost_first_anchored_nfa_default, - AC_LEFTMOST_FIRST_ANCHORED, - LeftmostFirst, - |b: &mut AhoCorasickBuilder| { - b.anchored(true); - } -); -testconfig!( - search_leftmost_first_anchored_dfa_default, - AC_LEFTMOST_FIRST_ANCHORED, - LeftmostFirst, - |b: &mut AhoCorasickBuilder| { - b.anchored(true).dfa(true); - } -); -testconfig!( - search_leftmost_longest_anchored_nfa_default, - AC_LEFTMOST_LONGEST_ANCHORED, - LeftmostLongest, - |b: &mut AhoCorasickBuilder| { - b.anchored(true); - } -); -testconfig!( - search_leftmost_longest_anchored_dfa_default, - AC_LEFTMOST_LONGEST_ANCHORED, - LeftmostLongest, - |b: &mut AhoCorasickBuilder| { - b.anchored(true).dfa(true); - } -); - -// And also write out the test combinations for ASCII case insensitivity. -testconfig!( - acasei_standard_nfa_default, - &[ASCII_CASE_INSENSITIVE], - Standard, - |b: &mut AhoCorasickBuilder| { - b.prefilter(false).ascii_case_insensitive(true); - } -); -testconfig!( - acasei_standard_dfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], - Standard, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true).dfa(true); - } -); -testconfig!( - overlapping, - acasei_standard_overlapping_nfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_OVERLAPPING], - Standard, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true); - } -); -testconfig!( - overlapping, - acasei_standard_overlapping_dfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_OVERLAPPING], - Standard, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true).dfa(true); - } -); -testconfig!( - acasei_leftmost_first_nfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], - LeftmostFirst, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true); - } -); -testconfig!( - acasei_leftmost_first_dfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], - LeftmostFirst, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true).dfa(true); - } -); -testconfig!( - acasei_leftmost_longest_nfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], - LeftmostLongest, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true); - } -); -testconfig!( - acasei_leftmost_longest_dfa_default, - &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], - LeftmostLongest, - |b: &mut AhoCorasickBuilder| { - b.ascii_case_insensitive(true).dfa(true); - } -); - -#[test] -fn search_tests_have_unique_names() { - let assert = |constname, tests: &[SearchTest]| { - let mut seen = HashMap::new(); // map from test name to position - for (i, test) in tests.iter().enumerate() { - if !seen.contains_key(test.name) { - seen.insert(test.name, i); - } else { - let last = seen[test.name]; - panic!( - "{} tests have duplicate names at positions {} and {}", - constname, last, i - ); - } - } - }; - assert("BASICS", BASICS); - assert("STANDARD", STANDARD); - assert("LEFTMOST", LEFTMOST); - assert("LEFTMOST_FIRST", LEFTMOST_FIRST); - assert("LEFTMOST_LONGEST", LEFTMOST_LONGEST); - assert("NON_OVERLAPPING", NON_OVERLAPPING); - assert("OVERLAPPING", OVERLAPPING); - assert("REGRESSION", REGRESSION); -} - -#[test] -#[should_panic] -fn stream_not_allowed_leftmost_first() { - let fsm = AhoCorasickBuilder::new() - .match_kind(MatchKind::LeftmostFirst) - .build(None::); - assert_eq!(fsm.stream_find_iter(&b""[..]).count(), 0); -} - -#[test] -#[should_panic] -fn stream_not_allowed_leftmost_longest() { - let fsm = AhoCorasickBuilder::new() - .match_kind(MatchKind::LeftmostLongest) - .build(None::); - assert_eq!(fsm.stream_find_iter(&b""[..]).count(), 0); -} - -#[test] -#[should_panic] -fn overlapping_not_allowed_leftmost_first() { - let fsm = AhoCorasickBuilder::new() - .match_kind(MatchKind::LeftmostFirst) - .build(None::); - assert_eq!(fsm.find_overlapping_iter("").count(), 0); -} - -#[test] -#[should_panic] -fn overlapping_not_allowed_leftmost_longest() { - let fsm = AhoCorasickBuilder::new() - .match_kind(MatchKind::LeftmostLongest) - .build(None::); - assert_eq!(fsm.find_overlapping_iter("").count(), 0); -} - -#[test] -fn state_id_too_small() { - let mut patterns = vec![]; - for c1 in (b'a'..b'z').map(|b| b as char) { - for c2 in (b'a'..b'z').map(|b| b as char) { - for c3 in (b'a'..b'z').map(|b| b as char) { - patterns.push(format!("{}{}{}", c1, c2, c3)); - } - } - } - let result = - AhoCorasickBuilder::new().build_with_size::(&patterns); - assert!(result.is_err()); -} - -// See: https://github.com/BurntSushi/aho-corasick/issues/44 -// -// In short, this test ensures that enabling ASCII case insensitivity does not -// visit an exponential number of states when filling in failure transitions. -#[test] -fn regression_ascii_case_insensitive_no_exponential() { - let ac = AhoCorasickBuilder::new() - .ascii_case_insensitive(true) - .build(&["Tsubaki House-Triple Shot Vol01校花三姐妹"]); - assert!(ac.find("").is_none()); -} - -// See: https://github.com/BurntSushi/aho-corasick/issues/53 -// -// This test ensures that the rare byte prefilter works in a particular corner -// case. In particular, the shift offset detected for '/' in the patterns below -// was incorrect, leading to a false negative. -#[test] -fn regression_rare_byte_prefilter() { - use AhoCorasick; - - let ac = AhoCorasick::new_auto_configured(&["ab/j/", "x/"]); - assert!(ac.is_match("ab/j/")); -} - -#[test] -fn regression_case_insensitive_prefilter() { - use AhoCorasickBuilder; - - for c in b'a'..b'z' { - for c2 in b'a'..b'z' { - let c = c as char; - let c2 = c2 as char; - let needle = format!("{}{}", c, c2).to_lowercase(); - let haystack = needle.to_uppercase(); - let ac = AhoCorasickBuilder::new() - .ascii_case_insensitive(true) - .prefilter(true) - .build(&[&needle]); - assert_eq!( - 1, - ac.find_iter(&haystack).count(), - "failed to find {:?} in {:?}\n\nautomaton:\n{:?}", - needle, - haystack, - ac, - ); - } - } -} - -fn run_search_tests Vec>( - which: TestCollection, - mut f: F, -) { - let get_match_triples = - |matches: Vec| -> Vec<(usize, usize, usize)> { - matches - .into_iter() - .map(|m| (m.pattern(), m.start(), m.end())) - .collect() - }; - for &tests in which { - for test in tests { - assert_eq!( - test.matches, - get_match_triples(f(&test)).as_slice(), - "test: {}, patterns: {:?}, haystack: {:?}", - test.name, - test.patterns, - test.haystack - ); - } - } -} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/.cargo-checksum.json b/third_party/cargo/vendor/aho-corasick-0.7.15/.cargo-checksum.json new file mode 100644 index 0000000..133666b --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"cf15db60c9989b860ea874785f1d8b1b5350a28501cd169831042837ee6f350c","DESIGN.md":"9065f33d818d1562244d36dc4781e2a351108030cee17f11c2ba512ca7b4c27e","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"88a0a32dce081f2b1a5c71f2208c155961b0171daf1a5a9a70371fc5cf0c4304","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/ahocorasick.rs":"00db7f3c3e9c764f7e2e620ee28baeebaf2101191218dd06b75d7656749a096f","src/automaton.rs":"ea3fc2648e026eac9f9969b0d457e49af7b4a40044379ce010d054f22afbc98f","src/buffer.rs":"dae7ee7c1f846ca9cf115ba4949484000e1837b4fb7311f8d8c9a35011c9c26f","src/byte_frequencies.rs":"2fb85b381c038c1e44ce94294531cdcd339dca48b1e61f41455666e802cbbc9e","src/classes.rs":"166c9f15c9a2e370e2bc9a9e1620bb2db13df52edfde9a0db1f20144519a7e72","src/dfa.rs":"8302d809d0acbf2a9d5f947d91e28d779cc547e49256961029f1c01e3375cba9","src/error.rs":"36dbf2cefbfaa8a69186551320dbff023d3e82780a6c925e87c3e3997b967e66","src/lib.rs":"2d2ef0070fb6c4ba6695e948e60e05ed63d3e8c31de28d3c112653798f95d6d3","src/nfa.rs":"3f68abf96a1c556021f0b7011634b3273b3df7e5366c9d27a2fc63e93ffbd95d","src/packed/api.rs":"6c65dfa177b7d7b79f90a048f260bec7f817126c693b85f49704c7d2ecf5f646","src/packed/mod.rs":"29c76ad3cbb1f831140cefac7a27fb504ac4af4f454975a571965b48aad417eb","src/packed/pattern.rs":"b88c57af057997da0a5a06f4c5604a7e598c20acfc11c15cd8977727f6e1cf9c","src/packed/rabinkarp.rs":"b3242a8631ea5607163dcbb641e4ac9c6da26774378da1e51651b0ab5656b390","src/packed/teddy/README.md":"5819f40d221af93288e705eadef5393a41d7a0900881b4d676e01fd65d5adf15","src/packed/teddy/compile.rs":"5d7de6a45a84bb2322647a6de7a7b1573837b9222b16e348f023b8d47e0a5130","src/packed/teddy/mod.rs":"f63db3419b1d378929bf0bc1f0e3b909ff3c38b9f2b6e86ba4546b8f39907cd3","src/packed/teddy/runtime.rs":"0a1250ea73159b3be6e0fa9a3f55ecedbb2cb90cb798d1709e9f5ee48f8855d5","src/packed/tests.rs":"0b52ab9eef73a1a4f141f475a9fa98e54d447104aa69acba3a7f8248ce7164b2","src/packed/vector.rs":"ab3c0535fca5f09198d58cbfae44c292aeb3ce44bc92bca36d30dc72963639fc","src/prefilter.rs":"5191cc8a273a909ca460c492357401cb664a66ed0505948e969786d655a9aed8","src/state_id.rs":"50958ca2b089d775fb4e49a64950e2f1e8a4af1772fe782ae3715a7745dcc6d7","src/tests.rs":"837bf7e7b9aa8b215a750475411730fa081370ee93e78a6f516d86280a1ab906"},"package":"7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"} \ No newline at end of file diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/BUILD.bazel b/third_party/cargo/vendor/aho-corasick-0.7.15/BUILD.bazel new file mode 100644 index 0000000..1611955 --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/BUILD.bazel @@ -0,0 +1,56 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "unencumbered", # Unlicense from expression "Unlicense OR MIT" +]) + +# Generated Targets + +rust_library( + name = "aho_corasick", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.7.15", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/memchr-2.3.4:memchr", + ], +) diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/COPYING b/third_party/cargo/vendor/aho-corasick-0.7.15/COPYING similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/COPYING rename to third_party/cargo/vendor/aho-corasick-0.7.15/COPYING diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/Cargo.toml b/third_party/cargo/vendor/aho-corasick-0.7.15/Cargo.toml new file mode 100644 index 0000000..38d89ae --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "aho-corasick" +version = "0.7.15" +authors = ["Andrew Gallant "] +exclude = ["/aho-corasick-debug", "/ci/*", "/.travis.yml", "/appveyor.yml"] +autotests = false +description = "Fast multiple substring searching." +homepage = "https://github.com/BurntSushi/aho-corasick" +readme = "README.md" +keywords = ["string", "search", "text", "aho", "multi"] +categories = ["text-processing"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/aho-corasick" +[profile.bench] +debug = true + +[profile.release] +debug = true + +[lib] +name = "aho_corasick" +[dependencies.memchr] +version = "2.2.0" +default-features = false +[dev-dependencies.doc-comment] +version = "0.3.1" + +[features] +default = ["std"] +std = ["memchr/use_std"] diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/DESIGN.md b/third_party/cargo/vendor/aho-corasick-0.7.15/DESIGN.md similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/DESIGN.md rename to third_party/cargo/vendor/aho-corasick-0.7.15/DESIGN.md diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/LICENSE-MIT b/third_party/cargo/vendor/aho-corasick-0.7.15/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/LICENSE-MIT rename to third_party/cargo/vendor/aho-corasick-0.7.15/LICENSE-MIT diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/README.md b/third_party/cargo/vendor/aho-corasick-0.7.15/README.md new file mode 100644 index 0000000..2f7a18e --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/README.md @@ -0,0 +1,187 @@ +aho-corasick +============ +A library for finding occurrences of many patterns at once with SIMD +acceleration in some cases. This library provides multiple pattern +search principally through an implementation of the +[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm), +which builds a finite state machine for executing searches in linear time. +Features include case insensitive matching, overlapping matches, fast searching +via SIMD and optional full DFA construction and search & replace in streams. + +[![Build status](https://github.com/BurntSushi/aho-corasick/workflows/ci/badge.svg)](https://github.com/BurntSushi/aho-corasick/actions) +[![](http://meritbadge.herokuapp.com/aho-corasick)](https://crates.io/crates/aho-corasick) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +https://docs.rs/aho-corasick + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +aho-corasick = "0.7" +``` + +and this to your crate root (if you're using Rust 2015): + +```rust +extern crate aho_corasick; +``` + + +### Example: basic searching + +This example shows how to search for occurrences of multiple patterns +simultaneously. Each match includes the pattern that matched along with the +byte offsets of the match. + +```rust +use aho_corasick::AhoCorasick; + +let patterns = &["apple", "maple", "Snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasick::new(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + + +### Example: case insensitivity + +This is like the previous example, but matches `Snapple` case insensitively +using `AhoCorasickBuilder`: + +```rust +use aho_corasick::AhoCorasickBuilder; + +let patterns = &["apple", "maple", "snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasickBuilder::new() + .ascii_case_insensitive(true) + .build(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + + +### Example: replacing matches in a stream + +This example shows how to execute a search and replace on a stream without +loading the entire stream into memory first. + +```rust +use aho_corasick::AhoCorasick; + +let patterns = &["fox", "brown", "quick"]; +let replace_with = &["sloth", "grey", "slow"]; + +// In a real example, these might be `std::fs::File`s instead. All you need to +// do is supply a pair of `std::io::Read` and `std::io::Write` implementations. +let rdr = "The quick brown fox."; +let mut wtr = vec![]; + +let ac = AhoCorasick::new(patterns); +ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with) + .expect("stream_replace_all failed"); +assert_eq!(b"The slow grey sloth.".to_vec(), wtr); +``` + + +### Example: finding the leftmost first match + +In the textbook description of Aho-Corasick, its formulation is typically +structured such that it reports all possible matches, even when they overlap +with another. In many cases, overlapping matches may not be desired, such as +the case of finding all successive non-overlapping matches like you might with +a standard regular expression. + +Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do +this doesn't always work in the expected way, since it will report matches as +soon as they are seen. For example, consider matching the regex `Samwise|Sam` +against the text `Samwise`. Most regex engines (that are Perl-like, or +non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick +algorithm modified for reporting non-overlapping matches will report `Sam`. + +A novel contribution of this library is the ability to change the match +semantics of Aho-Corasick (without additional search time overhead) such that +`Samwise` is reported instead. For example, here's the standard approach: + +```rust +use aho_corasick::AhoCorasick; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasick::new(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Sam", &haystack[mat.start()..mat.end()]); +``` + +And now here's the leftmost-first version, which matches how a Perl-like +regex will work: + +```rust +use aho_corasick::{AhoCorasickBuilder, MatchKind}; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Samwise", &haystack[mat.start()..mat.end()]); +``` + +In addition to leftmost-first semantics, this library also supports +leftmost-longest semantics, which match the POSIX behavior of a regular +expression alternation. See `MatchKind` in the docs for more details. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.28.0`. + +The current policy is that the minimum Rust version required to use this crate +can be increased in minor version updates. For example, if `crate 1.0` requires +Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust +1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum +version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. + + +### Future work + +Here are some plans for the future: + +* Assuming the current API is sufficient, I'd like to commit to it and release + a `1.0` version of this crate some time in the next 6-12 months. +* Support stream searching with leftmost match semantics. Currently, only + standard match semantics are supported. Getting this right seems possible, + but is tricky since the match state needs to be propagated through multiple + searches. (With standard semantics, as soon as a match is seen the search + ends.) diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/UNLICENSE b/third_party/cargo/vendor/aho-corasick-0.7.15/UNLICENSE similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/UNLICENSE rename to third_party/cargo/vendor/aho-corasick-0.7.15/UNLICENSE diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/rustfmt.toml b/third_party/cargo/vendor/aho-corasick-0.7.15/rustfmt.toml similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/rustfmt.toml rename to third_party/cargo/vendor/aho-corasick-0.7.15/rustfmt.toml diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/ahocorasick.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/ahocorasick.rs similarity index 96% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/ahocorasick.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/ahocorasick.rs index 9b7d9e7..9069396 100644 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/ahocorasick.rs +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/ahocorasick.rs @@ -6,7 +6,7 @@ use dfa::{self, DFA}; use error::Result; use nfa::{self, NFA}; use packed; -use prefilter::PrefilterState; +use prefilter::{Prefilter, PrefilterState}; use state_id::StateID; use Match; @@ -502,7 +502,7 @@ impl AhoCorasick { /// The closure accepts three parameters: the match found, the text of /// the match and a string buffer with which to write the replaced text /// (if any). If the closure returns `true`, then it continues to the next - /// match. If the closure returns false, then searching is stopped. + /// match. If the closure returns `false`, then searching is stopped. /// /// # Examples /// @@ -524,6 +524,24 @@ impl AhoCorasick { /// }); /// assert_eq!("0 the 2 to the 0age", result); /// ``` + /// + /// Stopping the replacement by returning `false` (continued from the + /// example above): + /// + /// ``` + /// # use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// # let patterns = &["append", "appendage", "app"]; + /// # let haystack = "append the app to the appendage"; + /// # let ac = AhoCorasickBuilder::new() + /// # .match_kind(MatchKind::LeftmostFirst) + /// # .build(patterns); + /// let mut result = String::new(); + /// ac.replace_all_with(haystack, &mut result, |mat, _, dst| { + /// dst.push_str(&mat.pattern().to_string()); + /// mat.pattern() != 2 + /// }); + /// assert_eq!("0 the 2 to the appendage", result); + /// ``` pub fn replace_all_with( &self, haystack: &str, @@ -536,7 +554,9 @@ impl AhoCorasick { for mat in self.find_iter(haystack) { dst.push_str(&haystack[last_match..mat.start()]); last_match = mat.end(); - replace_with(&mat, &haystack[mat.start()..mat.end()], dst); + if !replace_with(&mat, &haystack[mat.start()..mat.end()], dst) { + break; + }; } dst.push_str(&haystack[last_match..]); } @@ -548,7 +568,7 @@ impl AhoCorasick { /// The closure accepts three parameters: the match found, the text of /// the match and a byte buffer with which to write the replaced text /// (if any). If the closure returns `true`, then it continues to the next - /// match. If the closure returns false, then searching is stopped. + /// match. If the closure returns `false`, then searching is stopped. /// /// # Examples /// @@ -570,6 +590,24 @@ impl AhoCorasick { /// }); /// assert_eq!(b"0 the 2 to the 0age".to_vec(), result); /// ``` + /// + /// Stopping the replacement by returning `false` (continued from the + /// example above): + /// + /// ``` + /// # use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// # let patterns = &["append", "appendage", "app"]; + /// # let haystack = b"append the app to the appendage"; + /// # let ac = AhoCorasickBuilder::new() + /// # .match_kind(MatchKind::LeftmostFirst) + /// # .build(patterns); + /// let mut result = vec![]; + /// ac.replace_all_with_bytes(haystack, &mut result, |mat, _, dst| { + /// dst.extend(mat.pattern().to_string().bytes()); + /// mat.pattern() != 2 + /// }); + /// assert_eq!(b"0 the 2 to the appendage".to_vec(), result); + /// ``` pub fn replace_all_with_bytes( &self, haystack: &[u8], @@ -582,7 +620,9 @@ impl AhoCorasick { for mat in self.find_iter(haystack) { dst.extend(&haystack[last_match..mat.start()]); last_match = mat.end(); - replace_with(&mat, &haystack[mat.start()..mat.end()], dst); + if !replace_with(&mat, &haystack[mat.start()..mat.end()], dst) { + break; + }; } dst.extend(&haystack[last_match..]); } @@ -735,9 +775,7 @@ impl AhoCorasick { /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). /// /// The closure accepts three parameters: the match found, the text of - /// the match and the writer with which to write the replaced text - /// (if any). If the closure returns `true`, then it continues to the next - /// match. If the closure returns false, then searching is stopped. + /// the match and the writer with which to write the replaced text (if any). /// /// After all matches are replaced, the writer is _not_ flushed. /// @@ -1037,6 +1075,24 @@ impl Imp { } } + /// Returns the prefilter object, if one exists, for the underlying + /// automaton. + fn prefilter(&self) -> Option<&dyn Prefilter> { + match *self { + Imp::NFA(ref nfa) => nfa.prefilter(), + Imp::DFA(ref dfa) => dfa.prefilter(), + } + } + + /// Returns true if and only if we should attempt to use a prefilter. + fn use_prefilter(&self) -> bool { + let p = match self.prefilter() { + None => return false, + Some(p) => p, + }; + !p.looks_for_non_start_of_match() + } + #[inline(always)] fn overlapping_find_at( &self, @@ -1325,7 +1381,11 @@ impl<'a, R: io::Read, S: StateID> StreamChunkIter<'a, R, S> { "stream searching is only supported for Standard match semantics" ); - let prestate = PrefilterState::new(ac.max_pattern_len()); + let prestate = if ac.imp.use_prefilter() { + PrefilterState::new(ac.max_pattern_len()) + } else { + PrefilterState::disabled() + }; let buf = Buffer::new(ac.imp.max_pattern_len()); let state_id = ac.imp.start_state(); StreamChunkIter { @@ -1809,7 +1869,7 @@ impl AhoCorasickBuilder { /// finite automaton (NFA) is used instead. /// /// The main benefit to a DFA is that it can execute searches more quickly - /// than a DFA (perhaps 2-4 times as fast). The main drawback is that the + /// than a NFA (perhaps 2-4 times as fast). The main drawback is that the /// DFA uses more space and can take much longer to build. /// /// Enabling this option does not change the time complexity for diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/automaton.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/automaton.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/automaton.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/automaton.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/src/buffer.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/buffer.rs new file mode 100644 index 0000000..e7339eb --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/buffer.rs @@ -0,0 +1,132 @@ +use std::cmp; +use std::io; +use std::ptr; + +/// The default buffer capacity that we use for the stream buffer. +const DEFAULT_BUFFER_CAPACITY: usize = 8 * (1 << 10); // 8 KB + +/// A fairly simple roll buffer for supporting stream searches. +/// +/// This buffer acts as a temporary place to store a fixed amount of data when +/// reading from a stream. Its central purpose is to allow "rolling" some +/// suffix of the data to the beginning of the buffer before refilling it with +/// more data from the stream. For example, let's say we are trying to match +/// "foobar" on a stream. When we report the match, we'd like to not only +/// report the correct offsets at which the match occurs, but also the matching +/// bytes themselves. So let's say our stream is a file with the following +/// contents: `test test foobar test test`. Now assume that we happen to read +/// the aforementioned file in two chunks: `test test foo` and `bar test test`. +/// Naively, it would not be possible to report a single contiguous `foobar` +/// match, but this roll buffer allows us to do that. Namely, after the second +/// read, the contents of the buffer should be `st foobar test test`, where the +/// search should ultimately resume immediately after `foo`. (The prefix `st ` +/// is included because the roll buffer saves N bytes at the end of the buffer, +/// where N is the maximum possible length of a match.) +/// +/// A lot of the logic for dealing with this is unfortunately split out between +/// this roll buffer and the `StreamChunkIter`. +#[derive(Debug)] +pub struct Buffer { + /// The raw buffer contents. This has a fixed size and never increases. + buf: Vec, + /// The minimum size of the buffer, which is equivalent to the maximum + /// possible length of a match. This corresponds to the amount that we + /// roll + min: usize, + /// The end of the contents of this buffer. + end: usize, +} + +impl Buffer { + /// Create a new buffer for stream searching. The minimum buffer length + /// given should be the size of the maximum possible match length. + pub fn new(min_buffer_len: usize) -> Buffer { + let min = cmp::max(1, min_buffer_len); + // The minimum buffer amount is also the amount that we roll our + // buffer in order to support incremental searching. To this end, + // our actual capacity needs to be at least 1 byte bigger than our + // minimum amount, otherwise we won't have any overlap. In actuality, + // we want our buffer to be a bit bigger than that for performance + // reasons, so we set a lower bound of `8 * min`. + // + // TODO: It would be good to find a way to test the streaming + // implementation with the minimal buffer size. For now, we just + // uncomment out the next line and comment out the subsequent line. + // let capacity = 1 + min; + let capacity = cmp::max(min * 8, DEFAULT_BUFFER_CAPACITY); + Buffer { buf: vec![0; capacity], min, end: 0 } + } + + /// Return the contents of this buffer. + #[inline] + pub fn buffer(&self) -> &[u8] { + &self.buf[..self.end] + } + + /// Return the minimum size of the buffer. The only way a buffer may be + /// smaller than this is if the stream itself contains less than the + /// minimum buffer amount. + #[inline] + pub fn min_buffer_len(&self) -> usize { + self.min + } + + /// Return the total length of the contents in the buffer. + #[inline] + pub fn len(&self) -> usize { + self.end + } + + /// Return all free capacity in this buffer. + fn free_buffer(&mut self) -> &mut [u8] { + &mut self.buf[self.end..] + } + + /// Refill the contents of this buffer by reading as much as possible into + /// this buffer's free capacity. If no more bytes could be read, then this + /// returns false. Otherwise, this reads until it has filled the buffer + /// past the minimum amount. + pub fn fill(&mut self, mut rdr: R) -> io::Result { + let mut readany = false; + loop { + let readlen = rdr.read(self.free_buffer())?; + if readlen == 0 { + return Ok(readany); + } + readany = true; + self.end += readlen; + if self.len() >= self.min { + return Ok(true); + } + } + } + + /// Roll the contents of the buffer so that the suffix of this buffer is + /// moved to the front and all other contents are dropped. The size of the + /// suffix corresponds precisely to the minimum buffer length. + /// + /// This should only be called when the entire contents of this buffer have + /// been searched. + pub fn roll(&mut self) { + let roll_start = self + .end + .checked_sub(self.min) + .expect("buffer capacity should be bigger than minimum amount"); + let roll_len = self.min; + + assert!(roll_start + roll_len <= self.end); + unsafe { + // SAFETY: A buffer contains Copy data, so there's no problem + // moving it around. Safety also depends on our indices being in + // bounds, which they always should be, given the assert above. + // + // TODO: Switch to [T]::copy_within once our MSRV is high enough. + ptr::copy( + self.buf[roll_start..].as_ptr(), + self.buf.as_mut_ptr(), + roll_len, + ); + } + self.end = roll_len; + } +} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/byte_frequencies.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/byte_frequencies.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/byte_frequencies.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/byte_frequencies.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/classes.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/classes.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/classes.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/classes.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/src/dfa.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/dfa.rs new file mode 100644 index 0000000..8a4e727 --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/dfa.rs @@ -0,0 +1,713 @@ +use std::mem::size_of; + +use ahocorasick::MatchKind; +use automaton::Automaton; +use classes::ByteClasses; +use error::Result; +use nfa::{PatternID, PatternLength, NFA}; +use prefilter::{Prefilter, PrefilterObj, PrefilterState}; +use state_id::{dead_id, fail_id, premultiply_overflow_error, StateID}; +use Match; + +#[derive(Clone, Debug)] +pub enum DFA { + Standard(Standard), + ByteClass(ByteClass), + Premultiplied(Premultiplied), + PremultipliedByteClass(PremultipliedByteClass), +} + +impl DFA { + fn repr(&self) -> &Repr { + match *self { + DFA::Standard(ref dfa) => dfa.repr(), + DFA::ByteClass(ref dfa) => dfa.repr(), + DFA::Premultiplied(ref dfa) => dfa.repr(), + DFA::PremultipliedByteClass(ref dfa) => dfa.repr(), + } + } + + pub fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + pub fn heap_bytes(&self) -> usize { + self.repr().heap_bytes + } + + pub fn max_pattern_len(&self) -> usize { + self.repr().max_pattern_len + } + + pub fn pattern_count(&self) -> usize { + self.repr().pattern_count + } + + pub fn prefilter(&self) -> Option<&dyn Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + pub fn start_state(&self) -> S { + self.repr().start_id + } + + #[inline(always)] + pub fn overlapping_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + match_index: &mut usize, + ) -> Option { + match *self { + DFA::Standard(ref dfa) => dfa.overlapping_find_at( + prestate, + haystack, + at, + state_id, + match_index, + ), + DFA::ByteClass(ref dfa) => dfa.overlapping_find_at( + prestate, + haystack, + at, + state_id, + match_index, + ), + DFA::Premultiplied(ref dfa) => dfa.overlapping_find_at( + prestate, + haystack, + at, + state_id, + match_index, + ), + DFA::PremultipliedByteClass(ref dfa) => dfa.overlapping_find_at( + prestate, + haystack, + at, + state_id, + match_index, + ), + } + } + + #[inline(always)] + pub fn earliest_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + ) -> Option { + match *self { + DFA::Standard(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + DFA::ByteClass(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + DFA::Premultiplied(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + DFA::PremultipliedByteClass(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + } + } + + #[inline(always)] + pub fn find_at_no_state( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + ) -> Option { + match *self { + DFA::Standard(ref dfa) => { + dfa.find_at_no_state(prestate, haystack, at) + } + DFA::ByteClass(ref dfa) => { + dfa.find_at_no_state(prestate, haystack, at) + } + DFA::Premultiplied(ref dfa) => { + dfa.find_at_no_state(prestate, haystack, at) + } + DFA::PremultipliedByteClass(ref dfa) => { + dfa.find_at_no_state(prestate, haystack, at) + } + } + } +} + +#[derive(Clone, Debug)] +pub struct Standard(Repr); + +impl Standard { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for Standard { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn anchored(&self) -> bool { + self.repr().anchored + } + + fn prefilter(&self) -> Option<&dyn Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + id.to_usize() < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + self.repr().get_match(id, match_index, end) + } + + fn match_count(&self, id: S) -> usize { + self.repr().match_count(id) + } + + fn next_state(&self, current: S, input: u8) -> S { + let o = current.to_usize() * 256 + input as usize; + self.repr().trans[o] + } +} + +#[derive(Clone, Debug)] +pub struct ByteClass(Repr); + +impl ByteClass { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for ByteClass { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn anchored(&self) -> bool { + self.repr().anchored + } + + fn prefilter(&self) -> Option<&dyn Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + id.to_usize() < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + self.repr().get_match(id, match_index, end) + } + + fn match_count(&self, id: S) -> usize { + self.repr().match_count(id) + } + + fn next_state(&self, current: S, input: u8) -> S { + let alphabet_len = self.repr().byte_classes.alphabet_len(); + let input = self.repr().byte_classes.get(input); + let o = current.to_usize() * alphabet_len + input as usize; + self.repr().trans[o] + } +} + +#[derive(Clone, Debug)] +pub struct Premultiplied(Repr); + +impl Premultiplied { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for Premultiplied { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn anchored(&self) -> bool { + self.repr().anchored + } + + fn prefilter(&self) -> Option<&dyn Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + (id.to_usize() / 256) < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + if id > self.repr().max_match { + return None; + } + self.repr() + .matches + .get(id.to_usize() / 256) + .and_then(|m| m.get(match_index)) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + fn match_count(&self, id: S) -> usize { + let o = id.to_usize() / 256; + self.repr().matches[o].len() + } + + fn next_state(&self, current: S, input: u8) -> S { + let o = current.to_usize() + input as usize; + self.repr().trans[o] + } +} + +#[derive(Clone, Debug)] +pub struct PremultipliedByteClass(Repr); + +impl PremultipliedByteClass { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for PremultipliedByteClass { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn anchored(&self) -> bool { + self.repr().anchored + } + + fn prefilter(&self) -> Option<&dyn Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + (id.to_usize() / self.repr().alphabet_len()) < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + if id > self.repr().max_match { + return None; + } + self.repr() + .matches + .get(id.to_usize() / self.repr().alphabet_len()) + .and_then(|m| m.get(match_index)) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + fn match_count(&self, id: S) -> usize { + let o = id.to_usize() / self.repr().alphabet_len(); + self.repr().matches[o].len() + } + + fn next_state(&self, current: S, input: u8) -> S { + let input = self.repr().byte_classes.get(input); + let o = current.to_usize() + input as usize; + self.repr().trans[o] + } +} + +#[derive(Clone, Debug)] +pub struct Repr { + match_kind: MatchKind, + anchored: bool, + premultiplied: bool, + start_id: S, + /// The length, in bytes, of the longest pattern in this automaton. This + /// information is useful for keeping correct buffer sizes when searching + /// on streams. + max_pattern_len: usize, + /// The total number of patterns added to this automaton. This includes + /// patterns that may never match. + pattern_count: usize, + state_count: usize, + max_match: S, + /// The number of bytes of heap used by this NFA's transition table. + heap_bytes: usize, + /// A prefilter for quickly detecting candidate matchs, if pertinent. + prefilter: Option, + byte_classes: ByteClasses, + trans: Vec, + matches: Vec>, +} + +impl Repr { + /// Returns the total alphabet size for this DFA. + /// + /// If byte classes are enabled, then this corresponds to the number of + /// equivalence classes. If they are disabled, then this is always 256. + fn alphabet_len(&self) -> usize { + self.byte_classes.alphabet_len() + } + + /// Returns true only if the given state is a match state. + fn is_match_state(&self, id: S) -> bool { + id <= self.max_match && id > dead_id() + } + + /// Returns true only if the given state is either a dead state or a match + /// state. + fn is_match_or_dead_state(&self, id: S) -> bool { + id <= self.max_match + } + + /// Get the ith match for the given state, where the end position of a + /// match was found at `end`. + /// + /// # Panics + /// + /// The caller must ensure that the given state identifier is valid, + /// otherwise this may panic. The `match_index` need not be valid. That is, + /// if the given state has no matches then this returns `None`. + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + if id > self.max_match { + return None; + } + self.matches + .get(id.to_usize()) + .and_then(|m| m.get(match_index)) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + /// Return the total number of matches for the given state. + /// + /// # Panics + /// + /// The caller must ensure that the given identifier is valid, or else + /// this panics. + fn match_count(&self, id: S) -> usize { + self.matches[id.to_usize()].len() + } + + /// Get the next state given `from` as the current state and `byte` as the + /// current input byte. + fn next_state(&self, from: S, byte: u8) -> S { + let alphabet_len = self.alphabet_len(); + let byte = self.byte_classes.get(byte); + self.trans[from.to_usize() * alphabet_len + byte as usize] + } + + /// Set the `byte` transition for the `from` state to point to `to`. + fn set_next_state(&mut self, from: S, byte: u8, to: S) { + let alphabet_len = self.alphabet_len(); + let byte = self.byte_classes.get(byte); + self.trans[from.to_usize() * alphabet_len + byte as usize] = to; + } + + /// Swap the given states in place. + fn swap_states(&mut self, id1: S, id2: S) { + assert!(!self.premultiplied, "can't swap states in premultiplied DFA"); + + let o1 = id1.to_usize() * self.alphabet_len(); + let o2 = id2.to_usize() * self.alphabet_len(); + for b in 0..self.alphabet_len() { + self.trans.swap(o1 + b, o2 + b); + } + self.matches.swap(id1.to_usize(), id2.to_usize()); + } + + /// This routine shuffles all match states in this DFA to the beginning + /// of the DFA such that every non-match state appears after every match + /// state. (With one exception: the special fail and dead states remain as + /// the first two states.) + /// + /// The purpose of doing this shuffling is to avoid an extra conditional + /// in the search loop, and in particular, detecting whether a state is a + /// match or not does not need to access any memory. + /// + /// This updates `self.max_match` to point to the last matching state as + /// well as `self.start` if the starting state was moved. + fn shuffle_match_states(&mut self) { + assert!( + !self.premultiplied, + "cannot shuffle match states of premultiplied DFA" + ); + + if self.state_count <= 1 { + return; + } + + let mut first_non_match = self.start_id.to_usize(); + while first_non_match < self.state_count + && self.matches[first_non_match].len() > 0 + { + first_non_match += 1; + } + + let mut swaps: Vec = vec![fail_id(); self.state_count]; + let mut cur = self.state_count - 1; + while cur > first_non_match { + if self.matches[cur].len() > 0 { + self.swap_states( + S::from_usize(cur), + S::from_usize(first_non_match), + ); + swaps[cur] = S::from_usize(first_non_match); + swaps[first_non_match] = S::from_usize(cur); + + first_non_match += 1; + while first_non_match < cur + && self.matches[first_non_match].len() > 0 + { + first_non_match += 1; + } + } + cur -= 1; + } + for id in (0..self.state_count).map(S::from_usize) { + let alphabet_len = self.alphabet_len(); + let offset = id.to_usize() * alphabet_len; + for next in &mut self.trans[offset..offset + alphabet_len] { + if swaps[next.to_usize()] != fail_id() { + *next = swaps[next.to_usize()]; + } + } + } + if swaps[self.start_id.to_usize()] != fail_id() { + self.start_id = swaps[self.start_id.to_usize()]; + } + self.max_match = S::from_usize(first_non_match - 1); + } + + fn premultiply(&mut self) -> Result<()> { + if self.premultiplied || self.state_count <= 1 { + return Ok(()); + } + + let alpha_len = self.alphabet_len(); + premultiply_overflow_error( + S::from_usize(self.state_count - 1), + alpha_len, + )?; + + for id in (2..self.state_count).map(S::from_usize) { + let offset = id.to_usize() * alpha_len; + for next in &mut self.trans[offset..offset + alpha_len] { + if *next == dead_id() { + continue; + } + *next = S::from_usize(next.to_usize() * alpha_len); + } + } + self.premultiplied = true; + self.start_id = S::from_usize(self.start_id.to_usize() * alpha_len); + self.max_match = S::from_usize(self.max_match.to_usize() * alpha_len); + Ok(()) + } + + /// Computes the total amount of heap used by this NFA in bytes. + fn calculate_size(&mut self) { + let mut size = (self.trans.len() * size_of::()) + + (self.matches.len() + * size_of::>()); + for state_matches in &self.matches { + size += + state_matches.len() * size_of::<(PatternID, PatternLength)>(); + } + size += self.prefilter.as_ref().map_or(0, |p| p.as_ref().heap_bytes()); + self.heap_bytes = size; + } +} + +/// A builder for configuring the determinization of an NFA into a DFA. +#[derive(Clone, Debug)] +pub struct Builder { + premultiply: bool, + byte_classes: bool, +} + +impl Builder { + /// Create a new builder for a DFA. + pub fn new() -> Builder { + Builder { premultiply: true, byte_classes: true } + } + + /// Build a DFA from the given NFA. + /// + /// This returns an error if the state identifiers exceed their + /// representation size. This can only happen when state ids are + /// premultiplied (which is enabled by default). + pub fn build(&self, nfa: &NFA) -> Result> { + let byte_classes = if self.byte_classes { + nfa.byte_classes().clone() + } else { + ByteClasses::singletons() + }; + let alphabet_len = byte_classes.alphabet_len(); + let trans = vec![fail_id(); alphabet_len * nfa.state_len()]; + let matches = vec![vec![]; nfa.state_len()]; + let mut repr = Repr { + match_kind: nfa.match_kind().clone(), + anchored: nfa.anchored(), + premultiplied: false, + start_id: nfa.start_state(), + max_pattern_len: nfa.max_pattern_len(), + pattern_count: nfa.pattern_count(), + state_count: nfa.state_len(), + max_match: fail_id(), + heap_bytes: 0, + prefilter: nfa.prefilter_obj().map(|p| p.clone()), + byte_classes: byte_classes.clone(), + trans, + matches, + }; + for id in (0..nfa.state_len()).map(S::from_usize) { + repr.matches[id.to_usize()].extend_from_slice(nfa.matches(id)); + + let fail = nfa.failure_transition(id); + nfa.iter_all_transitions(&byte_classes, id, |b, mut next| { + if next == fail_id() { + next = nfa_next_state_memoized(nfa, &repr, id, fail, b); + } + repr.set_next_state(id, b, next); + }); + } + repr.shuffle_match_states(); + repr.calculate_size(); + if self.premultiply { + repr.premultiply()?; + if byte_classes.is_singleton() { + Ok(DFA::Premultiplied(Premultiplied(repr))) + } else { + Ok(DFA::PremultipliedByteClass(PremultipliedByteClass(repr))) + } + } else { + if byte_classes.is_singleton() { + Ok(DFA::Standard(Standard(repr))) + } else { + Ok(DFA::ByteClass(ByteClass(repr))) + } + } + } + + /// Whether to use byte classes or in the DFA. + pub fn byte_classes(&mut self, yes: bool) -> &mut Builder { + self.byte_classes = yes; + self + } + + /// Whether to premultiply state identifier in the DFA. + pub fn premultiply(&mut self, yes: bool) -> &mut Builder { + self.premultiply = yes; + self + } +} + +/// This returns the next NFA transition (including resolving failure +/// transitions), except once it sees a state id less than the id of the DFA +/// state that is currently being populated, then we no longer need to follow +/// failure transitions and can instead query the pre-computed state id from +/// the DFA itself. +/// +/// In general, this should only be called when a failure transition is seen. +fn nfa_next_state_memoized( + nfa: &NFA, + dfa: &Repr, + populating: S, + mut current: S, + input: u8, +) -> S { + loop { + if current < populating { + return dfa.next_state(current, input); + } + let next = nfa.next_state(current, input); + if next != fail_id() { + return next; + } + current = nfa.failure_transition(current); + } +} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/error.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/error.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/error.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/error.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/src/lib.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/lib.rs new file mode 100644 index 0000000..aa91c21 --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/lib.rs @@ -0,0 +1,298 @@ +/*! +A library for finding occurrences of many patterns at once. This library +provides multiple pattern search principally through an implementation of the +[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm), +which builds a fast finite state machine for executing searches in linear time. + +Additionally, this library provides a number of configuration options for +building the automaton that permit controlling the space versus time trade +off. Other features include simple ASCII case insensitive matching, finding +overlapping matches, replacements, searching streams and even searching and +replacing text in streams. + +Finally, unlike all other (known) Aho-Corasick implementations, this one +supports enabling +[leftmost-first](enum.MatchKind.html#variant.LeftmostFirst) +or +[leftmost-longest](enum.MatchKind.html#variant.LeftmostFirst) +match semantics, using a (seemingly) novel alternative construction algorithm. +For more details on what match semantics means, see the +[`MatchKind`](enum.MatchKind.html) +type. + +# Overview + +This section gives a brief overview of the primary types in this crate: + +* [`AhoCorasick`](struct.AhoCorasick.html) is the primary type and represents + an Aho-Corasick automaton. This is the type you use to execute searches. +* [`AhoCorasickBuilder`](struct.AhoCorasickBuilder.html) can be used to build + an Aho-Corasick automaton, and supports configuring a number of options. +* [`Match`](struct.Match.html) represents a single match reported by an + Aho-Corasick automaton. Each match has two pieces of information: the pattern + that matched and the start and end byte offsets corresponding to the position + in the haystack at which it matched. + +Additionally, the [`packed`](packed/index.html) sub-module contains a lower +level API for using fast vectorized routines for finding a small number of +patterns in a haystack. + +# Example: basic searching + +This example shows how to search for occurrences of multiple patterns +simultaneously. Each match includes the pattern that matched along with the +byte offsets of the match. + +``` +use aho_corasick::AhoCorasick; + +let patterns = &["apple", "maple", "Snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasick::new(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + +# Example: case insensitivity + +This is like the previous example, but matches `Snapple` case insensitively +using `AhoCorasickBuilder`: + +``` +use aho_corasick::AhoCorasickBuilder; + +let patterns = &["apple", "maple", "snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasickBuilder::new() + .ascii_case_insensitive(true) + .build(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + +# Example: replacing matches in a stream + +This example shows how to execute a search and replace on a stream without +loading the entire stream into memory first. + +``` +use aho_corasick::AhoCorasick; + +# fn example() -> Result<(), ::std::io::Error> { +let patterns = &["fox", "brown", "quick"]; +let replace_with = &["sloth", "grey", "slow"]; + +// In a real example, these might be `std::fs::File`s instead. All you need to +// do is supply a pair of `std::io::Read` and `std::io::Write` implementations. +let rdr = "The quick brown fox."; +let mut wtr = vec![]; + +let ac = AhoCorasick::new(patterns); +ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)?; +assert_eq!(b"The slow grey sloth.".to_vec(), wtr); +# Ok(()) }; example().unwrap() +``` + +# Example: finding the leftmost first match + +In the textbook description of Aho-Corasick, its formulation is typically +structured such that it reports all possible matches, even when they overlap +with another. In many cases, overlapping matches may not be desired, such as +the case of finding all successive non-overlapping matches like you might with +a standard regular expression. + +Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do +this doesn't always work in the expected way, since it will report matches as +soon as they are seen. For example, consider matching the regex `Samwise|Sam` +against the text `Samwise`. Most regex engines (that are Perl-like, or +non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick +algorithm modified for reporting non-overlapping matches will report `Sam`. + +A novel contribution of this library is the ability to change the match +semantics of Aho-Corasick (without additional search time overhead) such that +`Samwise` is reported instead. For example, here's the standard approach: + +``` +use aho_corasick::AhoCorasick; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasick::new(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Sam", &haystack[mat.start()..mat.end()]); +``` + +And now here's the leftmost-first version, which matches how a Perl-like +regex will work: + +``` +use aho_corasick::{AhoCorasickBuilder, MatchKind}; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Samwise", &haystack[mat.start()..mat.end()]); +``` + +In addition to leftmost-first semantics, this library also supports +leftmost-longest semantics, which match the POSIX behavior of a regular +expression alternation. See +[`MatchKind`](enum.MatchKind.html) +for more details. + +# Prefilters + +While an Aho-Corasick automaton can perform admirably when compared to more +naive solutions, it is generally slower than more specialized algorithms that +are accelerated using vector instructions such as SIMD. + +For that reason, this library will internally use a "prefilter" to attempt +to accelerate searches when possible. Currently, this library has several +different algorithms it might use depending on the patterns provided. Once the +number of patterns gets too big, prefilters are no longer used. + +While a prefilter is generally good to have on by default since it works +well in the common case, it can lead to less predictable or even sub-optimal +performance in some cases. For that reason, prefilters can be explicitly +disabled via +[`AhoCorasickBuilder::prefilter`](struct.AhoCorasickBuilder.html#method.prefilter). +*/ + +#![deny(missing_docs)] + +// We can never be truly no_std, but we could be alloc-only some day, so +// require the std feature for now. +#[cfg(not(feature = "std"))] +compile_error!("`std` feature is currently required to build this crate"); + +extern crate memchr; +// #[cfg(doctest)] +// #[macro_use] +// extern crate doc_comment; + +// #[cfg(doctest)] +// doctest!("../README.md"); + +pub use ahocorasick::{ + AhoCorasick, AhoCorasickBuilder, FindIter, FindOverlappingIter, MatchKind, + StreamFindIter, +}; +pub use error::{Error, ErrorKind}; +pub use state_id::StateID; + +mod ahocorasick; +mod automaton; +mod buffer; +mod byte_frequencies; +mod classes; +mod dfa; +mod error; +mod nfa; +pub mod packed; +mod prefilter; +mod state_id; +#[cfg(test)] +mod tests; + +/// A representation of a match reported by an Aho-Corasick automaton. +/// +/// A match has two essential pieces of information: the identifier of the +/// pattern that matched, along with the start and end offsets of the match +/// in the haystack. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use aho_corasick::AhoCorasick; +/// +/// let ac = AhoCorasick::new(&[ +/// "foo", "bar", "baz", +/// ]); +/// let mat = ac.find("xxx bar xxx").expect("should have a match"); +/// assert_eq!(1, mat.pattern()); +/// assert_eq!(4, mat.start()); +/// assert_eq!(7, mat.end()); +/// ``` +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Match { + /// The pattern id. + pattern: usize, + /// The length of this match, such that the starting position of the match + /// is `end - len`. + /// + /// We use length here because, other than the pattern id, the only + /// information about each pattern that the automaton stores is its length. + /// So using the length here is just a bit more natural. But it isn't + /// technically required. + len: usize, + /// The end offset of the match, exclusive. + end: usize, +} + +impl Match { + /// Returns the identifier of the pattern that matched. + /// + /// The identifier of a pattern is derived from the position in which it + /// was originally inserted into the corresponding automaton. The first + /// pattern has identifier `0`, and each subsequent pattern is `1`, `2` + /// and so on. + #[inline] + pub fn pattern(&self) -> usize { + self.pattern + } + + /// The starting position of the match. + #[inline] + pub fn start(&self) -> usize { + self.end - self.len + } + + /// The ending position of the match. + #[inline] + pub fn end(&self) -> usize { + self.end + } + + /// Returns true if and only if this match is empty. That is, when + /// `start() == end()`. + /// + /// An empty match can only be returned when the empty string was among + /// the patterns used to build the Aho-Corasick automaton. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + #[inline] + fn increment(&self, by: usize) -> Match { + Match { pattern: self.pattern, len: self.len, end: self.end + by } + } + + #[inline] + fn from_span(id: usize, start: usize, end: usize) -> Match { + Match { pattern: id, len: end - start, end } + } +} diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/nfa.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/nfa.rs similarity index 97% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/nfa.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/nfa.rs index 809d5ef..217be50 100644 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/nfa.rs +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/nfa.rs @@ -858,10 +858,17 @@ impl<'a, S: StateID> Compiler<'a, S> { while let Some(id) = queue.pop_front() { let mut it = self.nfa.iter_transitions_mut(id); while let Some((b, next)) = it.next() { - if !seen.contains(next) { - queue.push_back(next); - seen.insert(next); + if seen.contains(next) { + // The only way to visit a duplicate state in a transition + // list is when ASCII case insensitivity is enabled. In + // this case, we want to skip it since it's redundant work. + // But it would also end up duplicating matches, which + // results in reporting duplicate matches in some cases. + // See the 'acasei010' regression test. + continue; } + queue.push_back(next); + seen.insert(next); let mut fail = it.nfa().state(id).fail; while it.nfa().state(fail).next_state(b) == fail_id() { @@ -1012,10 +1019,17 @@ impl<'a, S: StateID> Compiler<'a, S> { // Queue up the next state. let next = item.next_queued_state(it.nfa(), next_id); - if !seen.contains(next.id) { - queue.push_back(next); - seen.insert(next.id); + if seen.contains(next.id) { + // The only way to visit a duplicate state in a transition + // list is when ASCII case insensitivity is enabled. In + // this case, we want to skip it since it's redundant work. + // But it would also end up duplicating matches, which + // results in reporting duplicate matches in some cases. + // See the 'acasei010' regression test. + continue; } + queue.push_back(next); + seen.insert(next.id); // Find the failure state for next. Same as standard. let mut fail = it.nfa().state(item.id).fail; diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/api.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/api.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/api.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/api.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/mod.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/mod.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/mod.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/mod.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/pattern.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/pattern.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/pattern.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/pattern.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/rabinkarp.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/rabinkarp.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/rabinkarp.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/rabinkarp.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/README.md b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/README.md similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/README.md rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/README.md diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/compile.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/compile.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/compile.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/compile.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/mod.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/mod.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/mod.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/mod.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/runtime.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/runtime.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/teddy/runtime.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/teddy/runtime.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/tests.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/tests.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/tests.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/tests.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/vector.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/vector.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/packed/vector.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/packed/vector.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/prefilter.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/prefilter.rs similarity index 92% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/prefilter.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/prefilter.rs index bda215d..05fa46d 100644 --- a/third_party/cargo/vendor/aho-corasick-0.7.10/src/prefilter.rs +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/prefilter.rs @@ -80,6 +80,17 @@ pub trait Prefilter: fn reports_false_positives(&self) -> bool { true } + + /// Returns true if and only if this prefilter may look for a non-starting + /// position of a match. + /// + /// This is useful in a streaming context where prefilters that don't look + /// for a starting position of a match can be quite difficult to deal with. + /// + /// This returns false by default. + fn looks_for_non_start_of_match(&self) -> bool { + false + } } impl<'a, P: Prefilter + ?Sized> Prefilter for &'a P { @@ -191,6 +202,17 @@ impl PrefilterState { } } + /// Create a prefilter state that always disables the prefilter. + pub fn disabled() -> PrefilterState { + PrefilterState { + skips: 0, + skipped: 0, + max_match_len: 0, + inert: true, + last_scan_at: 0, + } + } + /// Update this state with the number of bytes skipped on the last /// invocation of the prefilter. #[inline] @@ -285,6 +307,7 @@ impl Builder { /// All patterns added to an Aho-Corasick automaton should be added to this /// builder before attempting to construct the prefilter. pub fn build(&self) -> Option { + // match (self.start_bytes.build(), self.rare_bytes.build()) { match (self.start_bytes.build(), self.rare_bytes.build()) { // If we could build both start and rare prefilters, then there are // a few cases in which we'd want to use the start-byte prefilter @@ -663,6 +686,33 @@ impl Prefilter for RareBytesOne { fn heap_bytes(&self) -> usize { 0 } + + fn looks_for_non_start_of_match(&self) -> bool { + // TODO: It should be possible to use a rare byte prefilter in a + // streaming context. The main problem is that we usually assume that + // if a prefilter has scanned some text and not found anything, then no + // match *starts* in that text. This doesn't matter in non-streaming + // contexts, but in a streaming context, if we're looking for a byte + // that doesn't start at the beginning of a match and don't find it, + // then it's still possible for a match to start at the end of the + // current buffer content. In order to fix this, the streaming searcher + // would need to become aware of prefilters that do this and use the + // appropriate offset in various places. It is quite a delicate change + // and probably shouldn't be attempted until streaming search has a + // better testing strategy. In particular, we'd really like to be able + // to vary the buffer size to force strange cases that occur at the + // edge of the buffer. If we make the buffer size minimal, then these + // cases occur more frequently and easier. + // + // This is also a bummer because this means that if the prefilter + // builder chose a rare byte prefilter, then a streaming search won't + // use any prefilter at all because the builder doesn't know how it's + // going to be used. Assuming we don't make streaming search aware of + // these special types of prefilters as described above, we could fix + // this by building a "backup" prefilter that could be used when the + // rare byte prefilter could not. But that's a bandaide. Sigh. + true + } } /// A prefilter for scanning for two "rare" bytes. @@ -697,6 +747,11 @@ impl Prefilter for RareBytesTwo { fn heap_bytes(&self) -> usize { 0 } + + fn looks_for_non_start_of_match(&self) -> bool { + // TODO: See Prefilter impl for RareBytesOne. + true + } } /// A prefilter for scanning for three "rare" bytes. @@ -732,6 +787,11 @@ impl Prefilter for RareBytesThree { fn heap_bytes(&self) -> usize { 0 } + + fn looks_for_non_start_of_match(&self) -> bool { + // TODO: See Prefilter impl for RareBytesOne. + true + } } /// A builder for constructing a starting byte prefilter. diff --git a/third_party/cargo/vendor/aho-corasick-0.7.10/src/state_id.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/state_id.rs similarity index 100% rename from third_party/cargo/vendor/aho-corasick-0.7.10/src/state_id.rs rename to third_party/cargo/vendor/aho-corasick-0.7.15/src/state_id.rs diff --git a/third_party/cargo/vendor/aho-corasick-0.7.15/src/tests.rs b/third_party/cargo/vendor/aho-corasick-0.7.15/src/tests.rs new file mode 100644 index 0000000..668fbbf --- /dev/null +++ b/third_party/cargo/vendor/aho-corasick-0.7.15/src/tests.rs @@ -0,0 +1,1240 @@ +use std::collections::HashMap; +use std::io; +use std::usize; + +use {AhoCorasickBuilder, Match, MatchKind}; + +/// A description of a single test against an Aho-Corasick automaton. +/// +/// A single test may not necessarily pass on every configuration of an +/// Aho-Corasick automaton. The tests are categorized and grouped appropriately +/// below. +#[derive(Clone, Debug, Eq, PartialEq)] +struct SearchTest { + /// The name of this test, for debugging. + name: &'static str, + /// The patterns to search for. + patterns: &'static [&'static str], + /// The text to search. + haystack: &'static str, + /// Each match is a triple of (pattern_index, start, end), where + /// pattern_index is an index into `patterns` and `start`/`end` are indices + /// into `haystack`. + matches: &'static [(usize, usize, usize)], +} + +/// Short-hand constructor for SearchTest. We use it a lot below. +macro_rules! t { + ($name:ident, $patterns:expr, $haystack:expr, $matches:expr) => { + SearchTest { + name: stringify!($name), + patterns: $patterns, + haystack: $haystack, + matches: $matches, + } + }; +} + +/// A collection of test groups. +type TestCollection = &'static [&'static [SearchTest]]; + +// Define several collections corresponding to the different type of match +// semantics supported by Aho-Corasick. These collections have some overlap, +// but each collection should have some tests that no other collection has. + +/// Tests for Aho-Corasick's standard non-overlapping match semantics. +const AC_STANDARD_NON_OVERLAPPING: TestCollection = + &[BASICS, NON_OVERLAPPING, STANDARD, REGRESSION]; + +/// Tests for Aho-Corasick's anchored standard non-overlapping match semantics. +const AC_STANDARD_ANCHORED_NON_OVERLAPPING: TestCollection = + &[ANCHORED_BASICS, ANCHORED_NON_OVERLAPPING, STANDARD_ANCHORED]; + +/// Tests for Aho-Corasick's standard overlapping match semantics. +const AC_STANDARD_OVERLAPPING: TestCollection = + &[BASICS, OVERLAPPING, REGRESSION]; + +/// Tests for Aho-Corasick's anchored standard overlapping match semantics. +const AC_STANDARD_ANCHORED_OVERLAPPING: TestCollection = + &[ANCHORED_BASICS, ANCHORED_OVERLAPPING]; + +/// Tests for Aho-Corasick's leftmost-first match semantics. +const AC_LEFTMOST_FIRST: TestCollection = + &[BASICS, NON_OVERLAPPING, LEFTMOST, LEFTMOST_FIRST, REGRESSION]; + +/// Tests for Aho-Corasick's anchored leftmost-first match semantics. +const AC_LEFTMOST_FIRST_ANCHORED: TestCollection = &[ + ANCHORED_BASICS, + ANCHORED_NON_OVERLAPPING, + ANCHORED_LEFTMOST, + ANCHORED_LEFTMOST_FIRST, +]; + +/// Tests for Aho-Corasick's leftmost-longest match semantics. +const AC_LEFTMOST_LONGEST: TestCollection = + &[BASICS, NON_OVERLAPPING, LEFTMOST, LEFTMOST_LONGEST, REGRESSION]; + +/// Tests for Aho-Corasick's anchored leftmost-longest match semantics. +const AC_LEFTMOST_LONGEST_ANCHORED: TestCollection = &[ + ANCHORED_BASICS, + ANCHORED_NON_OVERLAPPING, + ANCHORED_LEFTMOST, + ANCHORED_LEFTMOST_LONGEST, +]; + +// Now define the individual tests that make up the collections above. + +/// A collection of tests for the Aho-Corasick algorithm that should always be +/// true regardless of match semantics. That is, all combinations of +/// leftmost-{shortest, first, longest} x {overlapping, non-overlapping} +/// should produce the same answer. +const BASICS: &'static [SearchTest] = &[ + t!(basic000, &[], "", &[]), + t!(basic001, &["a"], "", &[]), + t!(basic010, &["a"], "a", &[(0, 0, 1)]), + t!(basic020, &["a"], "aa", &[(0, 0, 1), (0, 1, 2)]), + t!(basic030, &["a"], "aaa", &[(0, 0, 1), (0, 1, 2), (0, 2, 3)]), + t!(basic040, &["a"], "aba", &[(0, 0, 1), (0, 2, 3)]), + t!(basic050, &["a"], "bba", &[(0, 2, 3)]), + t!(basic060, &["a"], "bbb", &[]), + t!(basic070, &["a"], "bababbbba", &[(0, 1, 2), (0, 3, 4), (0, 8, 9)]), + t!(basic100, &["aa"], "", &[]), + t!(basic110, &["aa"], "aa", &[(0, 0, 2)]), + t!(basic120, &["aa"], "aabbaa", &[(0, 0, 2), (0, 4, 6)]), + t!(basic130, &["aa"], "abbab", &[]), + t!(basic140, &["aa"], "abbabaa", &[(0, 5, 7)]), + t!(basic200, &["abc"], "abc", &[(0, 0, 3)]), + t!(basic210, &["abc"], "zazabzabcz", &[(0, 6, 9)]), + t!(basic220, &["abc"], "zazabczabcz", &[(0, 3, 6), (0, 7, 10)]), + t!(basic300, &["a", "b"], "", &[]), + t!(basic310, &["a", "b"], "z", &[]), + t!(basic320, &["a", "b"], "b", &[(1, 0, 1)]), + t!(basic330, &["a", "b"], "a", &[(0, 0, 1)]), + t!( + basic340, + &["a", "b"], + "abba", + &[(0, 0, 1), (1, 1, 2), (1, 2, 3), (0, 3, 4),] + ), + t!( + basic350, + &["b", "a"], + "abba", + &[(1, 0, 1), (0, 1, 2), (0, 2, 3), (1, 3, 4),] + ), + t!(basic360, &["abc", "bc"], "xbc", &[(1, 1, 3),]), + t!(basic400, &["foo", "bar"], "", &[]), + t!(basic410, &["foo", "bar"], "foobar", &[(0, 0, 3), (1, 3, 6),]), + t!(basic420, &["foo", "bar"], "barfoo", &[(1, 0, 3), (0, 3, 6),]), + t!(basic430, &["foo", "bar"], "foofoo", &[(0, 0, 3), (0, 3, 6),]), + t!(basic440, &["foo", "bar"], "barbar", &[(1, 0, 3), (1, 3, 6),]), + t!(basic450, &["foo", "bar"], "bafofoo", &[(0, 4, 7),]), + t!(basic460, &["bar", "foo"], "bafofoo", &[(1, 4, 7),]), + t!(basic470, &["foo", "bar"], "fobabar", &[(1, 4, 7),]), + t!(basic480, &["bar", "foo"], "fobabar", &[(0, 4, 7),]), + t!(basic600, &[""], "", &[(0, 0, 0)]), + t!(basic610, &[""], "a", &[(0, 0, 0), (0, 1, 1)]), + t!(basic620, &[""], "abc", &[(0, 0, 0), (0, 1, 1), (0, 2, 2), (0, 3, 3)]), + t!(basic700, &["yabcdef", "abcdezghi"], "yabcdefghi", &[(0, 0, 7),]), + t!(basic710, &["yabcdef", "abcdezghi"], "yabcdezghi", &[(1, 1, 10),]), + t!( + basic720, + &["yabcdef", "bcdeyabc", "abcdezghi"], + "yabcdezghi", + &[(2, 1, 10),] + ), +]; + +/// A collection of *anchored* tests for the Aho-Corasick algorithm that should +/// always be true regardless of match semantics. That is, all combinations of +/// leftmost-{shortest, first, longest} x {overlapping, non-overlapping} should +/// produce the same answer. +const ANCHORED_BASICS: &'static [SearchTest] = &[ + t!(abasic000, &[], "", &[]), + t!(abasic010, &[""], "", &[(0, 0, 0)]), + t!(abasic020, &[""], "a", &[(0, 0, 0)]), + t!(abasic030, &[""], "abc", &[(0, 0, 0)]), + t!(abasic100, &["a"], "a", &[(0, 0, 1)]), + t!(abasic110, &["a"], "aa", &[(0, 0, 1)]), + t!(abasic120, &["a", "b"], "ab", &[(0, 0, 1)]), + t!(abasic130, &["a", "b"], "ba", &[(1, 0, 1)]), + t!(abasic140, &["foo", "foofoo"], "foo", &[(0, 0, 3)]), + t!(abasic150, &["foofoo", "foo"], "foo", &[(1, 0, 3)]), +]; + +/// Tests for non-overlapping standard match semantics. +/// +/// These tests generally shouldn't pass for leftmost-{first,longest}, although +/// some do in order to write clearer tests. For example, standard000 will +/// pass with leftmost-first semantics, but standard010 will not. We write +/// both to emphasize how the match semantics work. +const STANDARD: &'static [SearchTest] = &[ + t!(standard000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), + t!(standard010, &["abcd", "ab"], "abcd", &[(1, 0, 2)]), + t!(standard020, &["abcd", "ab", "abc"], "abcd", &[(1, 0, 2)]), + t!(standard030, &["abcd", "abc", "ab"], "abcd", &[(2, 0, 2)]), + t!(standard040, &["a", ""], "a", &[(1, 0, 0), (1, 1, 1)]), + t!( + standard400, + &["abcd", "bcd", "cd", "b"], + "abcd", + &[(3, 1, 2), (2, 2, 4),] + ), + t!(standard410, &["", "a"], "a", &[(0, 0, 0), (0, 1, 1),]), + t!(standard420, &["", "a"], "aa", &[(0, 0, 0), (0, 1, 1), (0, 2, 2),]), + t!(standard430, &["", "a", ""], "a", &[(0, 0, 0), (0, 1, 1),]), + t!(standard440, &["a", "", ""], "a", &[(1, 0, 0), (1, 1, 1),]), + t!(standard450, &["", "", "a"], "a", &[(0, 0, 0), (0, 1, 1),]), +]; + +/// Like STANDARD, but for anchored searches. +const STANDARD_ANCHORED: &'static [SearchTest] = &[ + t!(astandard000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), + t!(astandard010, &["abcd", "ab"], "abcd", &[(1, 0, 2)]), + t!(astandard020, &["abcd", "ab", "abc"], "abcd", &[(1, 0, 2)]), + t!(astandard030, &["abcd", "abc", "ab"], "abcd", &[(2, 0, 2)]), + t!(astandard040, &["a", ""], "a", &[(1, 0, 0)]), + t!(astandard050, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4)]), + t!(astandard410, &["", "a"], "a", &[(0, 0, 0)]), + t!(astandard420, &["", "a"], "aa", &[(0, 0, 0)]), + t!(astandard430, &["", "a", ""], "a", &[(0, 0, 0)]), + t!(astandard440, &["a", "", ""], "a", &[(1, 0, 0)]), + t!(astandard450, &["", "", "a"], "a", &[(0, 0, 0)]), +]; + +/// Tests for non-overlapping leftmost match semantics. These should pass for +/// both leftmost-first and leftmost-longest match kinds. Stated differently, +/// among ambiguous matches, the longest match and the match that appeared +/// first when constructing the automaton should always be the same. +const LEFTMOST: &'static [SearchTest] = &[ + t!(leftmost000, &["ab", "ab"], "abcd", &[(0, 0, 2)]), + t!(leftmost010, &["a", ""], "a", &[(0, 0, 1), (1, 1, 1)]), + t!(leftmost020, &["", ""], "a", &[(0, 0, 0), (0, 1, 1)]), + t!(leftmost030, &["a", "ab"], "aa", &[(0, 0, 1), (0, 1, 2)]), + t!(leftmost031, &["ab", "a"], "aa", &[(1, 0, 1), (1, 1, 2)]), + t!(leftmost032, &["ab", "a"], "xayabbbz", &[(1, 1, 2), (0, 3, 5)]), + t!(leftmost300, &["abcd", "bce", "b"], "abce", &[(1, 1, 4)]), + t!(leftmost310, &["abcd", "ce", "bc"], "abce", &[(2, 1, 3)]), + t!(leftmost320, &["abcd", "bce", "ce", "b"], "abce", &[(1, 1, 4)]), + t!(leftmost330, &["abcd", "bce", "cz", "bc"], "abcz", &[(3, 1, 3)]), + t!(leftmost340, &["bce", "cz", "bc"], "bcz", &[(2, 0, 2)]), + t!(leftmost350, &["abc", "bd", "ab"], "abd", &[(2, 0, 2)]), + t!( + leftmost360, + &["abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(2, 0, 8),] + ), + t!( + leftmost370, + &["abcdefghi", "cde", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!( + leftmost380, + &["abcdefghi", "hz", "abcdefgh", "a"], + "abcdefghz", + &[(2, 0, 8),] + ), + t!( + leftmost390, + &["b", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!( + leftmost400, + &["h", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!( + leftmost410, + &["z", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8), (0, 8, 9),] + ), +]; + +/// Like LEFTMOST, but for anchored searches. +const ANCHORED_LEFTMOST: &'static [SearchTest] = &[ + t!(aleftmost000, &["ab", "ab"], "abcd", &[(0, 0, 2)]), + t!(aleftmost010, &["a", ""], "a", &[(0, 0, 1)]), + t!(aleftmost020, &["", ""], "a", &[(0, 0, 0)]), + t!(aleftmost030, &["a", "ab"], "aa", &[(0, 0, 1)]), + t!(aleftmost031, &["ab", "a"], "aa", &[(1, 0, 1)]), + t!(aleftmost032, &["ab", "a"], "xayabbbz", &[]), + t!(aleftmost300, &["abcd", "bce", "b"], "abce", &[]), + t!(aleftmost310, &["abcd", "ce", "bc"], "abce", &[]), + t!(aleftmost320, &["abcd", "bce", "ce", "b"], "abce", &[]), + t!(aleftmost330, &["abcd", "bce", "cz", "bc"], "abcz", &[]), + t!(aleftmost340, &["bce", "cz", "bc"], "bcz", &[(2, 0, 2)]), + t!(aleftmost350, &["abc", "bd", "ab"], "abd", &[(2, 0, 2)]), + t!( + aleftmost360, + &["abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(2, 0, 8),] + ), + t!( + aleftmost370, + &["abcdefghi", "cde", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!( + aleftmost380, + &["abcdefghi", "hz", "abcdefgh", "a"], + "abcdefghz", + &[(2, 0, 8),] + ), + t!( + aleftmost390, + &["b", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!( + aleftmost400, + &["h", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!( + aleftmost410, + &["z", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8)] + ), +]; + +/// Tests for non-overlapping leftmost-first match semantics. These tests +/// should generally be specific to leftmost-first, which means they should +/// generally fail under leftmost-longest semantics. +const LEFTMOST_FIRST: &'static [SearchTest] = &[ + t!(leftfirst000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), + t!(leftfirst010, &["", "a"], "a", &[(0, 0, 0), (0, 1, 1)]), + t!(leftfirst011, &["", "a", ""], "a", &[(0, 0, 0), (0, 1, 1),]), + t!(leftfirst012, &["a", "", ""], "a", &[(0, 0, 1), (1, 1, 1),]), + t!(leftfirst013, &["", "", "a"], "a", &[(0, 0, 0), (0, 1, 1),]), + t!(leftfirst020, &["abcd", "ab"], "abcd", &[(0, 0, 4)]), + t!(leftfirst030, &["ab", "ab"], "abcd", &[(0, 0, 2)]), + t!(leftfirst040, &["a", "ab"], "xayabbbz", &[(0, 1, 2), (0, 3, 4)]), + t!(leftfirst100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[(1, 1, 5)]), + t!(leftfirst110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[(1, 1, 6)]), + t!(leftfirst300, &["abcd", "b", "bce"], "abce", &[(1, 1, 2)]), + t!( + leftfirst310, + &["abcd", "b", "bce", "ce"], + "abce", + &[(1, 1, 2), (3, 2, 4),] + ), + t!( + leftfirst320, + &["a", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(0, 0, 1), (2, 7, 9),] + ), + t!(leftfirst330, &["a", "abab"], "abab", &[(0, 0, 1), (0, 2, 3)]), +]; + +/// Like LEFTMOST_FIRST, but for anchored searches. +const ANCHORED_LEFTMOST_FIRST: &'static [SearchTest] = &[ + t!(aleftfirst000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), + t!(aleftfirst010, &["", "a"], "a", &[(0, 0, 0)]), + t!(aleftfirst011, &["", "a", ""], "a", &[(0, 0, 0)]), + t!(aleftfirst012, &["a", "", ""], "a", &[(0, 0, 1)]), + t!(aleftfirst013, &["", "", "a"], "a", &[(0, 0, 0)]), + t!(aleftfirst020, &["abcd", "ab"], "abcd", &[(0, 0, 4)]), + t!(aleftfirst030, &["ab", "ab"], "abcd", &[(0, 0, 2)]), + t!(aleftfirst040, &["a", "ab"], "xayabbbz", &[]), + t!(aleftfirst100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[]), + t!(aleftfirst110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[]), + t!(aleftfirst300, &["abcd", "b", "bce"], "abce", &[]), + t!(aleftfirst310, &["abcd", "b", "bce", "ce"], "abce", &[]), + t!( + aleftfirst320, + &["a", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(0, 0, 1)] + ), + t!(aleftfirst330, &["a", "abab"], "abab", &[(0, 0, 1)]), +]; + +/// Tests for non-overlapping leftmost-longest match semantics. These tests +/// should generally be specific to leftmost-longest, which means they should +/// generally fail under leftmost-first semantics. +const LEFTMOST_LONGEST: &'static [SearchTest] = &[ + t!(leftlong000, &["ab", "abcd"], "abcd", &[(1, 0, 4)]), + t!(leftlong010, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4),]), + t!(leftlong020, &["", "a"], "a", &[(1, 0, 1), (0, 1, 1),]), + t!(leftlong021, &["", "a", ""], "a", &[(1, 0, 1), (0, 1, 1),]), + t!(leftlong022, &["a", "", ""], "a", &[(0, 0, 1), (1, 1, 1),]), + t!(leftlong023, &["", "", "a"], "a", &[(2, 0, 1), (0, 1, 1),]), + t!(leftlong030, &["", "a"], "aa", &[(1, 0, 1), (1, 1, 2), (0, 2, 2),]), + t!(leftlong040, &["a", "ab"], "a", &[(0, 0, 1)]), + t!(leftlong050, &["a", "ab"], "ab", &[(1, 0, 2)]), + t!(leftlong060, &["ab", "a"], "a", &[(1, 0, 1)]), + t!(leftlong070, &["ab", "a"], "ab", &[(0, 0, 2)]), + t!(leftlong100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[(2, 1, 6)]), + t!(leftlong110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[(1, 1, 6)]), + t!(leftlong300, &["abcd", "b", "bce"], "abce", &[(2, 1, 4)]), + t!( + leftlong310, + &["a", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!(leftlong320, &["a", "abab"], "abab", &[(1, 0, 4)]), + t!(leftlong330, &["abcd", "b", "ce"], "abce", &[(1, 1, 2), (2, 2, 4),]), + t!(leftlong340, &["a", "ab"], "xayabbbz", &[(0, 1, 2), (1, 3, 5)]), +]; + +/// Like LEFTMOST_LONGEST, but for anchored searches. +const ANCHORED_LEFTMOST_LONGEST: &'static [SearchTest] = &[ + t!(aleftlong000, &["ab", "abcd"], "abcd", &[(1, 0, 4)]), + t!(aleftlong010, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4),]), + t!(aleftlong020, &["", "a"], "a", &[(1, 0, 1)]), + t!(aleftlong021, &["", "a", ""], "a", &[(1, 0, 1)]), + t!(aleftlong022, &["a", "", ""], "a", &[(0, 0, 1)]), + t!(aleftlong023, &["", "", "a"], "a", &[(2, 0, 1)]), + t!(aleftlong030, &["", "a"], "aa", &[(1, 0, 1)]), + t!(aleftlong040, &["a", "ab"], "a", &[(0, 0, 1)]), + t!(aleftlong050, &["a", "ab"], "ab", &[(1, 0, 2)]), + t!(aleftlong060, &["ab", "a"], "a", &[(1, 0, 1)]), + t!(aleftlong070, &["ab", "a"], "ab", &[(0, 0, 2)]), + t!(aleftlong100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[]), + t!(aleftlong110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[]), + t!(aleftlong300, &["abcd", "b", "bce"], "abce", &[]), + t!( + aleftlong310, + &["a", "abcdefghi", "hz", "abcdefgh"], + "abcdefghz", + &[(3, 0, 8),] + ), + t!(aleftlong320, &["a", "abab"], "abab", &[(1, 0, 4)]), + t!(aleftlong330, &["abcd", "b", "ce"], "abce", &[]), + t!(aleftlong340, &["a", "ab"], "xayabbbz", &[]), +]; + +/// Tests for non-overlapping match semantics. +/// +/// Generally these tests shouldn't pass when using overlapping semantics. +/// These should pass for both standard and leftmost match semantics. +const NON_OVERLAPPING: &'static [SearchTest] = &[ + t!(nover010, &["abcd", "bcd", "cd"], "abcd", &[(0, 0, 4),]), + t!(nover020, &["bcd", "cd", "abcd"], "abcd", &[(2, 0, 4),]), + t!(nover030, &["abc", "bc"], "zazabcz", &[(0, 3, 6),]), + t!( + nover100, + &["ab", "ba"], + "abababa", + &[(0, 0, 2), (0, 2, 4), (0, 4, 6),] + ), + t!(nover200, &["foo", "foo"], "foobarfoo", &[(0, 0, 3), (0, 6, 9),]), + t!(nover300, &["", ""], "", &[(0, 0, 0),]), + t!(nover310, &["", ""], "a", &[(0, 0, 0), (0, 1, 1),]), +]; + +/// Like NON_OVERLAPPING, but for anchored searches. +const ANCHORED_NON_OVERLAPPING: &'static [SearchTest] = &[ + t!(anover010, &["abcd", "bcd", "cd"], "abcd", &[(0, 0, 4),]), + t!(anover020, &["bcd", "cd", "abcd"], "abcd", &[(2, 0, 4),]), + t!(anover030, &["abc", "bc"], "zazabcz", &[]), + t!(anover100, &["ab", "ba"], "abababa", &[(0, 0, 2)]), + t!(anover200, &["foo", "foo"], "foobarfoo", &[(0, 0, 3)]), + t!(anover300, &["", ""], "", &[(0, 0, 0),]), + t!(anover310, &["", ""], "a", &[(0, 0, 0)]), +]; + +/// Tests for overlapping match semantics. +/// +/// This only supports standard match semantics, since leftmost-{first,longest} +/// do not support overlapping matches. +const OVERLAPPING: &'static [SearchTest] = &[ + t!( + over000, + &["abcd", "bcd", "cd", "b"], + "abcd", + &[(3, 1, 2), (0, 0, 4), (1, 1, 4), (2, 2, 4),] + ), + t!( + over010, + &["bcd", "cd", "b", "abcd"], + "abcd", + &[(2, 1, 2), (3, 0, 4), (0, 1, 4), (1, 2, 4),] + ), + t!( + over020, + &["abcd", "bcd", "cd"], + "abcd", + &[(0, 0, 4), (1, 1, 4), (2, 2, 4),] + ), + t!( + over030, + &["bcd", "abcd", "cd"], + "abcd", + &[(1, 0, 4), (0, 1, 4), (2, 2, 4),] + ), + t!( + over040, + &["bcd", "cd", "abcd"], + "abcd", + &[(2, 0, 4), (0, 1, 4), (1, 2, 4),] + ), + t!(over050, &["abc", "bc"], "zazabcz", &[(0, 3, 6), (1, 4, 6),]), + t!( + over100, + &["ab", "ba"], + "abababa", + &[(0, 0, 2), (1, 1, 3), (0, 2, 4), (1, 3, 5), (0, 4, 6), (1, 5, 7),] + ), + t!( + over200, + &["foo", "foo"], + "foobarfoo", + &[(0, 0, 3), (1, 0, 3), (0, 6, 9), (1, 6, 9),] + ), + t!(over300, &["", ""], "", &[(0, 0, 0), (1, 0, 0),]), + t!( + over310, + &["", ""], + "a", + &[(0, 0, 0), (1, 0, 0), (0, 1, 1), (1, 1, 1),] + ), + t!(over320, &["", "a"], "a", &[(0, 0, 0), (1, 0, 1), (0, 1, 1),]), + t!( + over330, + &["", "a", ""], + "a", + &[(0, 0, 0), (2, 0, 0), (1, 0, 1), (0, 1, 1), (2, 1, 1),] + ), + t!( + over340, + &["a", "", ""], + "a", + &[(1, 0, 0), (2, 0, 0), (0, 0, 1), (1, 1, 1), (2, 1, 1),] + ), + t!( + over350, + &["", "", "a"], + "a", + &[(0, 0, 0), (1, 0, 0), (2, 0, 1), (0, 1, 1), (1, 1, 1),] + ), + t!( + over360, + &["foo", "foofoo"], + "foofoo", + &[(0, 0, 3), (1, 0, 6), (0, 3, 6)] + ), +]; + +/// Like OVERLAPPING, but for anchored searches. +const ANCHORED_OVERLAPPING: &'static [SearchTest] = &[ + t!(aover000, &["abcd", "bcd", "cd", "b"], "abcd", &[(0, 0, 4)]), + t!(aover010, &["bcd", "cd", "b", "abcd"], "abcd", &[(3, 0, 4)]), + t!(aover020, &["abcd", "bcd", "cd"], "abcd", &[(0, 0, 4)]), + t!(aover030, &["bcd", "abcd", "cd"], "abcd", &[(1, 0, 4)]), + t!(aover040, &["bcd", "cd", "abcd"], "abcd", &[(2, 0, 4)]), + t!(aover050, &["abc", "bc"], "zazabcz", &[]), + t!(aover100, &["ab", "ba"], "abababa", &[(0, 0, 2)]), + t!(aover200, &["foo", "foo"], "foobarfoo", &[(0, 0, 3), (1, 0, 3)]), + t!(aover300, &["", ""], "", &[(0, 0, 0), (1, 0, 0),]), + t!(aover310, &["", ""], "a", &[(0, 0, 0), (1, 0, 0)]), + t!(aover320, &["", "a"], "a", &[(0, 0, 0), (1, 0, 1)]), + t!(aover330, &["", "a", ""], "a", &[(0, 0, 0), (2, 0, 0), (1, 0, 1)]), + t!(aover340, &["a", "", ""], "a", &[(1, 0, 0), (2, 0, 0), (0, 0, 1)]), + t!(aover350, &["", "", "a"], "a", &[(0, 0, 0), (1, 0, 0), (2, 0, 1)]), + t!(aover360, &["foo", "foofoo"], "foofoo", &[(0, 0, 3), (1, 0, 6)]), +]; + +/// Tests for ASCII case insensitivity. +/// +/// These tests should all have the same behavior regardless of match semantics +/// or whether the search is overlapping. +const ASCII_CASE_INSENSITIVE: &'static [SearchTest] = &[ + t!(acasei000, &["a"], "A", &[(0, 0, 1)]), + t!(acasei010, &["Samwise"], "SAMWISE", &[(0, 0, 7)]), + t!(acasei011, &["Samwise"], "SAMWISE.abcd", &[(0, 0, 7)]), + t!(acasei020, &["fOoBaR"], "quux foobar baz", &[(0, 5, 11)]), +]; + +/// Like ASCII_CASE_INSENSITIVE, but specifically for non-overlapping tests. +const ASCII_CASE_INSENSITIVE_NON_OVERLAPPING: &'static [SearchTest] = &[ + t!(acasei000, &["foo", "FOO"], "fOo", &[(0, 0, 3)]), + t!(acasei000, &["FOO", "foo"], "fOo", &[(0, 0, 3)]), + t!(acasei010, &["abc", "def"], "abcdef", &[(0, 0, 3), (1, 3, 6)]), +]; + +/// Like ASCII_CASE_INSENSITIVE, but specifically for overlapping tests. +const ASCII_CASE_INSENSITIVE_OVERLAPPING: &'static [SearchTest] = &[ + t!(acasei000, &["foo", "FOO"], "fOo", &[(0, 0, 3), (1, 0, 3)]), + t!(acasei001, &["FOO", "foo"], "fOo", &[(0, 0, 3), (1, 0, 3)]), + // This is a regression test from: + // https://github.com/BurntSushi/aho-corasick/issues/68 + // Previously, it was reporting a duplicate (1, 3, 6) match. + t!( + acasei010, + &["abc", "def", "abcdef"], + "abcdef", + &[(0, 0, 3), (2, 0, 6), (1, 3, 6)] + ), +]; + +/// Regression tests that are applied to all Aho-Corasick combinations. +/// +/// If regression tests are needed for specific match semantics, then add them +/// to the appropriate group above. +const REGRESSION: &'static [SearchTest] = &[ + t!(regression010, &["inf", "ind"], "infind", &[(0, 0, 3), (1, 3, 6),]), + t!(regression020, &["ind", "inf"], "infind", &[(1, 0, 3), (0, 3, 6),]), + t!( + regression030, + &["libcore/", "libstd/"], + "libcore/char/methods.rs", + &[(0, 0, 8),] + ), + t!( + regression040, + &["libstd/", "libcore/"], + "libcore/char/methods.rs", + &[(1, 0, 8),] + ), + t!( + regression050, + &["\x00\x00\x01", "\x00\x00\x00"], + "\x00\x00\x00", + &[(1, 0, 3),] + ), + t!( + regression060, + &["\x00\x00\x00", "\x00\x00\x01"], + "\x00\x00\x00", + &[(0, 0, 3),] + ), +]; + +// Now define a test for each combination of things above that we want to run. +// Since there are a few different combinations for each collection of tests, +// we define a couple of macros to avoid repetition drudgery. The testconfig +// macro constructs the automaton from a given match kind, and runs the search +// tests one-by-one over the given collection. The `with` parameter allows one +// to configure the builder with additional parameters. The testcombo macro +// invokes testconfig in precisely this way: it sets up several tests where +// each one turns a different knob on AhoCorasickBuilder. + +macro_rules! testconfig { + (overlapping, $name:ident, $collection:expr, $kind:ident, $with:expr) => { + #[test] + fn $name() { + run_search_tests($collection, |test| { + let mut builder = AhoCorasickBuilder::new(); + $with(&mut builder); + builder + .match_kind(MatchKind::$kind) + .build(test.patterns) + .find_overlapping_iter(test.haystack) + .collect() + }); + } + }; + (stream, $name:ident, $collection:expr, $kind:ident, $with:expr) => { + #[test] + fn $name() { + run_search_tests($collection, |test| { + let buf = + io::BufReader::with_capacity(1, test.haystack.as_bytes()); + let mut builder = AhoCorasickBuilder::new(); + $with(&mut builder); + builder + .match_kind(MatchKind::$kind) + .build(test.patterns) + .stream_find_iter(buf) + .map(|result| result.unwrap()) + .collect() + }); + } + }; + ($name:ident, $collection:expr, $kind:ident, $with:expr) => { + #[test] + fn $name() { + run_search_tests($collection, |test| { + let mut builder = AhoCorasickBuilder::new(); + $with(&mut builder); + builder + .match_kind(MatchKind::$kind) + .build(test.patterns) + .find_iter(test.haystack) + .collect() + }); + } + }; +} + +macro_rules! testcombo { + ($name:ident, $collection:expr, $kind:ident) => { + mod $name { + use super::*; + + testconfig!(nfa_default, $collection, $kind, |_| ()); + testconfig!( + nfa_no_prefilter, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.prefilter(false); + } + ); + testconfig!( + nfa_all_sparse, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dense_depth(0); + } + ); + testconfig!( + nfa_all_dense, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dense_depth(usize::MAX); + } + ); + testconfig!( + dfa_default, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true); + } + ); + testconfig!( + dfa_no_prefilter, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).prefilter(false); + } + ); + testconfig!( + dfa_all_sparse, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).dense_depth(0); + } + ); + testconfig!( + dfa_all_dense, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).dense_depth(usize::MAX); + } + ); + testconfig!( + dfa_no_byte_class, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false); + } + ); + testconfig!( + dfa_no_premultiply, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).premultiply(false); + } + ); + testconfig!( + dfa_no_byte_class_no_premultiply, + $collection, + $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false).premultiply(false); + } + ); + } + }; +} + +// Write out the combinations. +testcombo!(search_leftmost_longest, AC_LEFTMOST_LONGEST, LeftmostLongest); +testcombo!(search_leftmost_first, AC_LEFTMOST_FIRST, LeftmostFirst); +testcombo!( + search_standard_nonoverlapping, + AC_STANDARD_NON_OVERLAPPING, + Standard +); + +// Write out the overlapping combo by hand since there is only one of them. +testconfig!( + overlapping, + search_standard_overlapping_nfa_default, + AC_STANDARD_OVERLAPPING, + Standard, + |_| () +); +testconfig!( + overlapping, + search_standard_overlapping_nfa_all_sparse, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dense_depth(0); + } +); +testconfig!( + overlapping, + search_standard_overlapping_nfa_all_dense, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dense_depth(usize::MAX); + } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_default, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true); + } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_all_sparse, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).dense_depth(0); + } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_all_dense, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).dense_depth(usize::MAX); + } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_no_byte_class, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false); + } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_no_premultiply, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).premultiply(false); + } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_no_byte_class_no_premultiply, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false).premultiply(false); + } +); + +// Also write out tests manually for streams, since we only test the standard +// match semantics. We also don't bother testing different automaton +// configurations, since those are well covered by tests above. +testconfig!( + stream, + search_standard_stream_nfa_default, + AC_STANDARD_NON_OVERLAPPING, + Standard, + |_| () +); +testconfig!( + stream, + search_standard_stream_dfa_default, + AC_STANDARD_NON_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true); + } +); + +// Same thing for anchored searches. Write them out manually. +testconfig!( + search_standard_anchored_nfa_default, + AC_STANDARD_ANCHORED_NON_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.anchored(true); + } +); +testconfig!( + search_standard_anchored_dfa_default, + AC_STANDARD_ANCHORED_NON_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.anchored(true).dfa(true); + } +); +testconfig!( + overlapping, + search_standard_anchored_overlapping_nfa_default, + AC_STANDARD_ANCHORED_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.anchored(true); + } +); +testconfig!( + overlapping, + search_standard_anchored_overlapping_dfa_default, + AC_STANDARD_ANCHORED_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.anchored(true).dfa(true); + } +); +testconfig!( + search_leftmost_first_anchored_nfa_default, + AC_LEFTMOST_FIRST_ANCHORED, + LeftmostFirst, + |b: &mut AhoCorasickBuilder| { + b.anchored(true); + } +); +testconfig!( + search_leftmost_first_anchored_dfa_default, + AC_LEFTMOST_FIRST_ANCHORED, + LeftmostFirst, + |b: &mut AhoCorasickBuilder| { + b.anchored(true).dfa(true); + } +); +testconfig!( + search_leftmost_longest_anchored_nfa_default, + AC_LEFTMOST_LONGEST_ANCHORED, + LeftmostLongest, + |b: &mut AhoCorasickBuilder| { + b.anchored(true); + } +); +testconfig!( + search_leftmost_longest_anchored_dfa_default, + AC_LEFTMOST_LONGEST_ANCHORED, + LeftmostLongest, + |b: &mut AhoCorasickBuilder| { + b.anchored(true).dfa(true); + } +); + +// And also write out the test combinations for ASCII case insensitivity. +testconfig!( + acasei_standard_nfa_default, + &[ASCII_CASE_INSENSITIVE], + Standard, + |b: &mut AhoCorasickBuilder| { + b.prefilter(false).ascii_case_insensitive(true); + } +); +testconfig!( + acasei_standard_dfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], + Standard, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true).dfa(true); + } +); +testconfig!( + overlapping, + acasei_standard_overlapping_nfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_OVERLAPPING], + Standard, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true); + } +); +testconfig!( + overlapping, + acasei_standard_overlapping_dfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_OVERLAPPING], + Standard, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true).dfa(true); + } +); +testconfig!( + acasei_leftmost_first_nfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], + LeftmostFirst, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true); + } +); +testconfig!( + acasei_leftmost_first_dfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], + LeftmostFirst, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true).dfa(true); + } +); +testconfig!( + acasei_leftmost_longest_nfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], + LeftmostLongest, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true); + } +); +testconfig!( + acasei_leftmost_longest_dfa_default, + &[ASCII_CASE_INSENSITIVE, ASCII_CASE_INSENSITIVE_NON_OVERLAPPING], + LeftmostLongest, + |b: &mut AhoCorasickBuilder| { + b.ascii_case_insensitive(true).dfa(true); + } +); + +fn run_search_tests Vec>( + which: TestCollection, + mut f: F, +) { + let get_match_triples = + |matches: Vec| -> Vec<(usize, usize, usize)> { + matches + .into_iter() + .map(|m| (m.pattern(), m.start(), m.end())) + .collect() + }; + for &tests in which { + for test in tests { + assert_eq!( + test.matches, + get_match_triples(f(&test)).as_slice(), + "test: {}, patterns: {:?}, haystack: {:?}", + test.name, + test.patterns, + test.haystack + ); + } + } +} + +#[test] +fn search_tests_have_unique_names() { + let assert = |constname, tests: &[SearchTest]| { + let mut seen = HashMap::new(); // map from test name to position + for (i, test) in tests.iter().enumerate() { + if !seen.contains_key(test.name) { + seen.insert(test.name, i); + } else { + let last = seen[test.name]; + panic!( + "{} tests have duplicate names at positions {} and {}", + constname, last, i + ); + } + } + }; + assert("BASICS", BASICS); + assert("STANDARD", STANDARD); + assert("LEFTMOST", LEFTMOST); + assert("LEFTMOST_FIRST", LEFTMOST_FIRST); + assert("LEFTMOST_LONGEST", LEFTMOST_LONGEST); + assert("NON_OVERLAPPING", NON_OVERLAPPING); + assert("OVERLAPPING", OVERLAPPING); + assert("REGRESSION", REGRESSION); +} + +#[test] +#[should_panic] +fn stream_not_allowed_leftmost_first() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(None::); + assert_eq!(fsm.stream_find_iter(&b""[..]).count(), 0); +} + +#[test] +#[should_panic] +fn stream_not_allowed_leftmost_longest() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostLongest) + .build(None::); + assert_eq!(fsm.stream_find_iter(&b""[..]).count(), 0); +} + +#[test] +#[should_panic] +fn overlapping_not_allowed_leftmost_first() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(None::); + assert_eq!(fsm.find_overlapping_iter("").count(), 0); +} + +#[test] +#[should_panic] +fn overlapping_not_allowed_leftmost_longest() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostLongest) + .build(None::); + assert_eq!(fsm.find_overlapping_iter("").count(), 0); +} + +#[test] +fn state_id_too_small() { + let mut patterns = vec![]; + for c1 in (b'a'..b'z').map(|b| b as char) { + for c2 in (b'a'..b'z').map(|b| b as char) { + for c3 in (b'a'..b'z').map(|b| b as char) { + patterns.push(format!("{}{}{}", c1, c2, c3)); + } + } + } + let result = + AhoCorasickBuilder::new().build_with_size::(&patterns); + assert!(result.is_err()); +} + +// See: https://github.com/BurntSushi/aho-corasick/issues/44 +// +// In short, this test ensures that enabling ASCII case insensitivity does not +// visit an exponential number of states when filling in failure transitions. +#[test] +fn regression_ascii_case_insensitive_no_exponential() { + let ac = AhoCorasickBuilder::new() + .ascii_case_insensitive(true) + .build(&["Tsubaki House-Triple Shot Vol01校花三姐妹"]); + assert!(ac.find("").is_none()); +} + +// See: https://github.com/BurntSushi/aho-corasick/issues/53 +// +// This test ensures that the rare byte prefilter works in a particular corner +// case. In particular, the shift offset detected for '/' in the patterns below +// was incorrect, leading to a false negative. +#[test] +fn regression_rare_byte_prefilter() { + use AhoCorasick; + + let ac = AhoCorasick::new_auto_configured(&["ab/j/", "x/"]); + assert!(ac.is_match("ab/j/")); +} + +#[test] +fn regression_case_insensitive_prefilter() { + use AhoCorasickBuilder; + + for c in b'a'..b'z' { + for c2 in b'a'..b'z' { + let c = c as char; + let c2 = c2 as char; + let needle = format!("{}{}", c, c2).to_lowercase(); + let haystack = needle.to_uppercase(); + let ac = AhoCorasickBuilder::new() + .ascii_case_insensitive(true) + .prefilter(true) + .build(&[&needle]); + assert_eq!( + 1, + ac.find_iter(&haystack).count(), + "failed to find {:?} in {:?}\n\nautomaton:\n{:?}", + needle, + haystack, + ac, + ); + } + } +} + +// See: https://github.com/BurntSushi/aho-corasick/issues/64 +// +// This occurs when the rare byte prefilter is active. +#[test] +fn regression_stream_rare_byte_prefilter() { + use std::io::Read; + + // NOTE: The test only fails if this ends with j. + const MAGIC: [u8; 5] = *b"1234j"; + + // NOTE: The test fails for value in 8188..=8191 These value put the string + // to search accross two call to read because the buffer size is 8192 by + // default. + const BEGIN: usize = 8191; + + /// This is just a structure that implements Reader. The reader + /// implementation will simulate a file filled with 0, except for the MAGIC + /// string at offset BEGIN. + #[derive(Default)] + struct R { + read: usize, + } + + impl Read for R { + fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result { + //dbg!(buf.len()); + if self.read > 100000 { + return Ok(0); + } + let mut from = 0; + if self.read < BEGIN { + from = buf.len().min(BEGIN - self.read); + for x in 0..from { + buf[x] = 0; + } + self.read += from; + } + if self.read >= BEGIN && self.read <= BEGIN + MAGIC.len() { + let to = buf.len().min(BEGIN + MAGIC.len() - self.read + from); + if to > from { + buf[from..to].copy_from_slice( + &MAGIC + [self.read - BEGIN..self.read - BEGIN + to - from], + ); + self.read += to - from; + from = to; + } + } + for x in from..buf.len() { + buf[x] = 0; + self.read += 1; + } + Ok(buf.len()) + } + } + + fn run() -> ::std::io::Result<()> { + let aut = AhoCorasickBuilder::new().build(&[&MAGIC]); + + // While reading from a vector, it works: + let mut buf = vec![]; + R::default().read_to_end(&mut buf)?; + let from_whole = aut.find_iter(&buf).next().unwrap().start(); + + //But using stream_find_iter fails! + let mut file = R::default(); + let begin = aut + .stream_find_iter(&mut file) + .next() + .expect("NOT FOUND!!!!")? // Panic here + .start(); + assert_eq!(from_whole, begin); + Ok(()) + } + + run().unwrap() +} diff --git a/third_party/cargo/vendor/andrew-0.2.1/.cargo-checksum.json b/third_party/cargo/vendor/andrew-0.2.1/.cargo-checksum.json deleted file mode 100644 index 2be56f8..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"4d03cdc2987a1fa1b86a2de5fa57714d83cbb9d3d3f400eadecd8e8a0a857621","Cargo.toml":"a9ec8b36707f907971b410719b85e9594cb96c9e4bca6f831e2cc78ba22c71da","LICENSE":"0dd39f89842df915b8ded7ac59e8a1372cf5be36133818866cca2ef3af1a2849","README.md":"132383b73044b1e91acb9e5d69afeb8f14239cfe712aca59152bfe0c420f7a33","examples/test.rs":"4e9e73dfe80573296e93f66c2c03681908c278a758dceb4913ecb65d20e9ed86","src/lib.rs":"7a0e852a4bbfbf72c7702527d7c6f7f8c717fca77bfd4b3e78ba7f6cebed4e6f","src/line.rs":"edbdc54503342733f8aa7a4aa72a7cb08d376d53ca2b85e00a77dd42bf04bb22","src/shapes/mod.rs":"071d6ea4080dc8f1e4299258d65c32bccc40e9eb6933f3b3600576d58e7917ae","src/shapes/rectangle.rs":"ad545b9d4a628b3a515deb9b087f881b253d3f3a16a60734da82896d51c93cc9","src/text/fontconfig.rs":"c673bfcf5df387479dd2027a733d8de85461731b448202f49a9f2d1bce54f465","src/text/mod.rs":"4afd25c6297d55cd5a3956e5ae6d3921403b306533a237fe2e5eab33e65a91ee"},"package":"9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e"} \ No newline at end of file diff --git a/third_party/cargo/vendor/andrew-0.2.1/BUILD.bazel b/third_party/cargo/vendor/andrew-0.2.1/BUILD.bazel deleted file mode 100644 index 320b3b1..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/BUILD.bazel +++ /dev/null @@ -1,61 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT" -]) - -# Generated Targets - -# Unsupported target "test" with type "example" omitted - -rust_library( - name = "andrew", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.2.1", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", - "//third_party/cargo/vendor/line_drawing-0.7.0:line_drawing", - "//third_party/cargo/vendor/walkdir-2.3.1:walkdir", - "//third_party/cargo/vendor/xdg-2.2.0:xdg", - "//third_party/cargo/vendor/xml-rs-0.8.3:xml_rs", - "//third_party/cargo/vendor/rusttype-0.8.3:rusttype", - ], -) diff --git a/third_party/cargo/vendor/andrew-0.2.1/CHANGELOG.md b/third_party/cargo/vendor/andrew-0.2.1/CHANGELOG.md deleted file mode 100644 index 79dad8c..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/CHANGELOG.md +++ /dev/null @@ -1,47 +0,0 @@ -# Change Log - -## Unreleased - -## 0.2.1 -- 2019-03-29 - -- Fix `get_width()` for texts that start and end with spaces - -## 0.2.0 -- 2019-01-26 - -- **[Breaking]** Canvas is now endian aware and will draw to the buffer in the endianness of the `Endian` its created with - -## 0.1.6 -- 2019-01-24 - -- Faster drawing of horizontal and verticle lines by precomputing line boundaries -- Only calculate alpha overlay when drawing colors without a non-max alpha value for performance - -## 0.1.5 -- 2019-01-13 - -- Fix drawing of characters with negative bounding boxes -- Fix error in `get_width()` for text without any characters - -## 0.1.4 -- 2018-11-10 - -- Remove rusttype version restriction - -## 0.1.3 -- 2018-10-09 - -- Move from `quick-xml` to `xml-rs` dependency - -## 0.1.2 -- 2018-10-04 - -- Add basic/experimental support for fontconfig in `andrew::text::fontconfig` - -## 0.1.1 -- 2018-09-17 - -- Manage dependencies to maintain rust 1.22 compatibility -- Update rusttype to 0.7.1 - -## 0.1.0 -- 2018-08-17 - -Initial version, including: - -- canvas -- lines -- rectangles -- text diff --git a/third_party/cargo/vendor/andrew-0.2.1/Cargo.toml b/third_party/cargo/vendor/andrew-0.2.1/Cargo.toml deleted file mode 100644 index 2b8b020..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "andrew" -version = "0.2.1" -authors = ["Lucas Timmins "] -description = "The andrew crate provides convenient drawing of objects such as shapes, lines and text to buffers" -readme = "README.md" -keywords = ["draw", "buffer", "shapes", "lines", "pixels"] -categories = ["rendering", "multimedia::images"] -license = "MIT" -repository = "https://github.com/trimental/andrew" -[dependencies.bitflags] -version = "1.0.3" - -[dependencies.line_drawing] -version = "0.7.0" - -[dependencies.rusttype] -version = "0.7.1" - -[dependencies.walkdir] -version = "2.0" - -[dependencies.xdg] -version = "2.1.0" - -[dependencies.xml-rs] -version = "0.8.0" -[dev-dependencies.smithay-client-toolkit] -version = "0.4.0" diff --git a/third_party/cargo/vendor/andrew-0.2.1/README.md b/third_party/cargo/vendor/andrew-0.2.1/README.md deleted file mode 100644 index 3b93ff7..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Andrew - -This crate provides convenient drawing of objects such as shapes, lines and text to buffers diff --git a/third_party/cargo/vendor/andrew-0.2.1/examples/test.rs b/third_party/cargo/vendor/andrew-0.2.1/examples/test.rs deleted file mode 100644 index 0d378e3..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/examples/test.rs +++ /dev/null @@ -1,210 +0,0 @@ -extern crate andrew; -extern crate smithay_client_toolkit as sctk; - -use std::io::{Read, Seek, SeekFrom, Write}; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant}; - -use sctk::utils::{DoubleMemPool, MemPool}; -use sctk::window::{ConceptFrame, Event as WEvent, Window}; -use sctk::Environment; - -use sctk::reexports::client::protocol::wl_compositor::RequestsTrait as CompositorRequests; -use sctk::reexports::client::protocol::wl_surface::RequestsTrait as SurfaceRequests; -use sctk::reexports::client::protocol::{wl_shm, wl_surface}; -use sctk::reexports::client::{Display, Proxy}; - -use andrew::shapes::rectangle; -use andrew::text; -use andrew::text::fontconfig; - -fn main() { - let (display, mut event_queue) = - Display::connect_to_env().expect("Failed to connect to the wayland server."); - let env = Environment::from_display(&*display, &mut event_queue).unwrap(); - - let seat = env - .manager - .instantiate_auto(|seat| seat.implement(|_, _| {}, ())) - .unwrap(); - - let mut dimensions = (600, 400); - let surface = env - .compositor - .create_surface(|surface| surface.implement(|_, _| {}, ())) - .unwrap(); - - let next_action = Arc::new(Mutex::new(None::)); - - let waction = next_action.clone(); - let mut window = Window::::init_from_env(&env, surface, dimensions, move |evt| { - let mut next_action = waction.lock().unwrap(); - // Keep last event in priority order : Close > Configure > Refresh - let replace = match (&evt, &*next_action) { - (_, &None) - | (_, &Some(WEvent::Refresh)) - | (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. })) - | (&WEvent::Close, _) => true, - _ => false, - }; - if replace { - *next_action = Some(evt); - } - }) - .expect("Failed to create a window !"); - - window.new_seat(&seat); - - let mut pools = DoubleMemPool::new(&env.shm, || {}).expect("Failed to create a memory pool !"); - - let mut font_data = Vec::new(); - ::std::fs::File::open( - &fontconfig::FontConfig::new() - .unwrap() - .get_regular_family_fonts("sans") - .unwrap()[0], - ) - .unwrap() - .read_to_end(&mut font_data) - .unwrap(); - - if !env.shell.needs_configure() { - if let Some(pool) = pools.pool() { - redraw(pool, window.surface(), dimensions, &font_data); - } - window.refresh(); - } - - loop { - match next_action.lock().unwrap().take() { - Some(WEvent::Close) => break, - Some(WEvent::Refresh) => { - window.refresh(); - window.surface().commit(); - } - Some(WEvent::Configure { new_size, .. }) => { - if let Some((w, h)) = new_size { - window.resize(w, h); - dimensions = (w, h) - } - window.refresh(); - if let Some(pool) = pools.pool() { - redraw(pool, window.surface(), dimensions, &font_data); - } - } - None => {} - } - - display.flush().unwrap(); - event_queue.dispatch().unwrap(); - } -} - -fn redraw( - pool: &mut MemPool, - surface: &Proxy, - dimensions: (u32, u32), - font_data: &[u8], -) { - let (buf_x, buf_y) = (dimensions.0 as usize, dimensions.1 as usize); - - pool.resize(4 * buf_x * buf_y) - .expect("Failed to resize the memory pool."); - - let mut buf: Vec = vec![255; 4 * buf_x * buf_y]; - let mut canvas = - andrew::Canvas::new(&mut buf, buf_x, buf_y, 4 * buf_x, andrew::Endian::native()); - - println!("______________"); - let mut total_dur = Duration::new(0, 0); - - // Draw background - let (block_w, block_h) = (buf_x / 20, buf_y / 20); - for block_y in 0..21 { - for block_x in 0..21 { - let color = if (block_x + (block_y % 2)) % 2 == 0 { - [255, 0, 0, 0] - } else { - [255, 255, 255, 255] - }; - - let block = rectangle::Rectangle::new( - (block_w * block_x, block_h * block_y), - (block_w, block_h), - None, - Some(color), - ); - let timer = Instant::now(); - canvas.draw(&block); - total_dur += timer.elapsed() - } - } - println!("Background draw time: {:?}", total_dur); - - let rectangle = rectangle::Rectangle::new( - (buf_x / 30, buf_y / 4), - (buf_x - (buf_x / 30) * 2, buf_y - buf_y / 2), - Some(( - 15, - [255, 170, 20, 45], - rectangle::Sides::TOP ^ rectangle::Sides::BOTTOM, - Some(10), - )), - Some([255, 170, 20, 45]), - ); - let mut timer = Instant::now(); - canvas.draw(&rectangle); - println!("Rectangle draw time: {:?}", timer.elapsed()); - total_dur += timer.elapsed(); - - let text_h = buf_x as f32 / 80.; - let text_hh = text_h / 2.; - let mut text = text::Text::new( - (63, 69), - [255, 255, 255, 255], - font_data, - text_h, - 2.0, - "“Life is the art of drawing without an eraser.” - John W. Gardner", - ); - text.pos = ( - buf_x / 2 - text.get_width() / 2, - buf_y / 2 - text_hh as usize, - ); - - let text_box = rectangle::Rectangle::new( - ( - buf_x / 2 - text.get_width() / 2 - 10, - buf_y / 2 - text_hh as usize - 10, - ), - (text.get_width() + 20, text_h as usize + 20), - Some((3, [255, 255, 255, 255], rectangle::Sides::ALL, Some(5))), - None, - ); - - timer = Instant::now(); - canvas.draw(&text_box); - println!("Text box draw time: {:?}", timer.elapsed()); - total_dur += timer.elapsed(); - - timer = Instant::now(); - canvas.draw(&text); - println!("Text draw time: {:?}", timer.elapsed()); - total_dur += timer.elapsed(); - - println!("Total draw time: {:?}", total_dur); - - pool.seek(SeekFrom::Start(0)).unwrap(); - pool.write_all(canvas.buffer).unwrap(); - pool.flush().unwrap(); - - let new_buffer = pool.buffer( - 0, - buf_x as i32, - buf_y as i32, - 4 * buf_x as i32, - wl_shm::Format::Argb8888, - ); - surface.attach(Some(&new_buffer), 0, 0); - surface.commit(); -} diff --git a/third_party/cargo/vendor/andrew-0.2.1/src/lib.rs b/third_party/cargo/vendor/andrew-0.2.1/src/lib.rs deleted file mode 100644 index 86f3e79..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/src/lib.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! Andrew is a crate for drawing objects -#![warn(missing_docs)] -extern crate line_drawing; -extern crate rusttype; -extern crate walkdir; -extern crate xdg; -extern crate xml; - -#[macro_use] -extern crate bitflags; - -/// A module that contains functions and objects relating to lines -pub mod line; -/// A module that contains functions and objects relating to shapes -pub mod shapes; -/// A module that contains functions and objects relating to text -pub mod text; - -/// The Drawable trait allows object to be drawn to a buffer or canvas -pub trait Drawable { - /// A function that draws the object to a canvas - fn draw(&self, canvas: &mut Canvas); -} - -/// Describes an endianness (aka byte order) -#[derive(Debug, PartialEq)] -pub enum Endian { - /// Little Endian - Little, - /// Big Endian - Big, -} - -impl Endian { - /// Returns the native endianness - pub fn native() -> Endian { - if cfg!(target_endian = "little") { - Endian::Little - } else { - Endian::Big - } - } -} - -/// The canvas object acts as a wrapper around a buffer, providing information and functions -/// for drawing -pub struct Canvas<'a> { - /// A buffer for the canvas to draw to - pub buffer: &'a mut [u8], - /// The width in pixels of the canvas - pub width: usize, - /// The height in pixels of the canvas - pub height: usize, - /// The number of bytes between each line of pixels on the canvas - pub stride: usize, - /// The number of bytes contained in each pixel - pub pixel_size: usize, - /// The endianness of the canvas - pub endianness: Endian, -} - -impl<'a> Canvas<'a> { - /// Creates a new canvas object - pub fn new( - buffer: &'a mut [u8], - width: usize, - height: usize, - stride: usize, - endianness: Endian, - ) -> Canvas<'a> { - assert!( - stride % width == 0, - "Incorrect Dimensions - Stride is not a multiple of width" - ); - assert!(buffer.len() == stride * height); - let pixel_size = stride / width; - Canvas { - buffer, - width, - height, - stride, - pixel_size, - endianness, - } - } - - /// Draws an object that implements the Drawable trait to the buffer - pub fn draw(&mut self, drawable: &D) { - drawable.draw(self); - } - - /// Draws a pixel at the x and y coordinate - pub fn draw_point(&mut self, x: usize, y: usize, color: [u8; 4]) { - let base = self.stride * y + self.pixel_size * x; - if self.endianness == Endian::Little { - if color[0] == 255 { - self.buffer[base + 3] = color[0]; - self.buffer[base + 2] = color[1]; - self.buffer[base + 1] = color[2]; - self.buffer[base] = color[3]; - } else { - for c in 0..3 { - let alpha = f32::from(color[0]) / 255.0; - let color_diff = - (color[3 - c] as isize - self.buffer[base + c] as isize) as f32 * alpha; - let new_color = (f32::from(self.buffer[base + c]) + color_diff) as u8; - self.buffer[base + c] = new_color as u8; - } - self.buffer[base + 3] = 255 as u8; - } - } else if color[0] == 255 { - self.buffer[base] = color[0]; - self.buffer[base + 1] = color[1]; - self.buffer[base + 2] = color[2]; - self.buffer[base + 3] = color[3]; - } else { - for c in 1..4 { - let alpha = f32::from(color[0]) / 255.0; - let color_diff = - (color[c] as isize - self.buffer[base + c] as isize) as f32 * alpha; - let new_color = (f32::from(self.buffer[base + c]) + color_diff) as u8; - self.buffer[base + c] = new_color as u8; - } - self.buffer[base] = 255 as u8; - } - } - - /// Clears the entire canvas buffer by zeroing it - pub fn clear(&mut self) { - for i in 0..self.width * self.height * 4 { - self.buffer[i] = 0x00; - } - } -} diff --git a/third_party/cargo/vendor/andrew-0.2.1/src/line.rs b/third_party/cargo/vendor/andrew-0.2.1/src/line.rs deleted file mode 100644 index 5179ae1..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/src/line.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::cmp::min; - -use line_drawing::Bresenham; -use line_drawing::XiaolinWu; - -use Canvas; -use Drawable; - -/// A drawable object that represents a line -pub struct Line { - /// The first point of the line - pub pt1: (usize, usize), - /// The second point of the line - pub pt2: (usize, usize), - /// The color of the line - pub color: [u8; 4], - /// Decides whether the line will be antialiased - pub antialiased: bool, -} - -impl Line { - /// Creates a new Line object - pub fn new( - pt1: (usize, usize), - pt2: (usize, usize), - color: [u8; 4], - antialiased: bool, - ) -> Line { - Line { - pt1, - pt2, - color, - antialiased, - } - } -} - -impl Drawable for Line { - fn draw(&self, canvas: &mut Canvas) { - if !self.antialiased { - if self.pt1.0 == self.pt2.0 && self.pt1.0 < canvas.width { - let (min_y, max_y) = if self.pt1.1 > self.pt2.1 { - (self.pt2.1, self.pt1.1) - } else { - (self.pt1.1, self.pt2.1) - }; - for y in min_y..min(max_y, canvas.height - 1) + 1 { - canvas.draw_point(self.pt1.0, y, self.color) - } - } else if self.pt1.1 == self.pt2.1 && self.pt1.1 < canvas.height { - let (min_x, max_x) = if self.pt1.0 > self.pt2.0 { - (self.pt2.0, self.pt1.0) - } else { - (self.pt1.0, self.pt2.0) - }; - for x in min_x..min(max_x, canvas.width - 1) + 1 { - canvas.draw_point(x, self.pt1.1, self.color) - } - } else { - // Angled line without antialias - for (x, y) in Bresenham::new( - (self.pt1.0 as isize, self.pt1.1 as isize), - (self.pt2.0 as isize, self.pt2.1 as isize), - ) { - if x < canvas.width as isize && y < canvas.height as isize { - canvas.draw_point(x as usize, y as usize, self.color) - } - } - } - } else { - // Angled line with antialias - for ((x, y), coverage) in XiaolinWu::::new( - (self.pt1.0 as f32, self.pt1.1 as f32), - (self.pt2.0 as f32, self.pt2.1 as f32), - ) { - if x < canvas.width as isize && y < canvas.height as isize { - let mut color = self.color; - color[3] = (f32::from(color[3]) * coverage) as u8; - canvas.draw_point(x as usize, y as usize, color) - } - } - } - } -} diff --git a/third_party/cargo/vendor/andrew-0.2.1/src/shapes/rectangle.rs b/third_party/cargo/vendor/andrew-0.2.1/src/shapes/rectangle.rs deleted file mode 100644 index d568fcf..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/src/shapes/rectangle.rs +++ /dev/null @@ -1,153 +0,0 @@ -use line::Line; -use Canvas; -use Drawable; - -bitflags! { - /// The Sides bitflag presents the sides of a rectangle - pub struct Sides: u32 { - /// The top side of the rectangle - const TOP = 0b0001; - /// The bottom side of the rectangle - const BOTTOM = 0b0010; - /// The left side of the rectangle - const LEFT = 0b0100; - /// The right side of the rectangle - const RIGHT = 0b1000; - /// All sides of the rectangle - const ALL = Self::TOP.bits | Self::BOTTOM.bits | Self::LEFT.bits | Self::RIGHT.bits; - } -} - -/// A drawable object that represents a rectangle -pub struct Rectangle { - /// Position of the top-left corner of rectangle - pub pos: (usize, usize), - /// The size of the rectangle to be drawn, the border will be contained within this size - pub size: (usize, usize), - /// The border that is drawn around the perimeter of the rectangle. It's arguments are - /// thickness of border, color of border, sides that the border is drawn around, rounding size - /// of the corners - pub border: Option<(usize, [u8; 4], Sides, Option)>, - /// The color of the fill (area) of the rectangle - pub fill: Option<[u8; 4]>, -} - -impl Rectangle { - /// Creates a new Rectangle object - pub fn new( - pos: (usize, usize), - size: (usize, usize), - border: Option<(usize, [u8; 4], Sides, Option)>, - fill: Option<[u8; 4]>, - ) -> Rectangle { - Rectangle { - pos, - size, - border, - fill, - } - } - - fn draw_borders(&self, canvas: &mut Canvas) { - if let Some(border) = self.border { - for i in 0..border.0 { - let rounding_space = if let Some(round_size) = border.3 { - if i < round_size { - round_size - - ((round_size as f32).powi(2) - ((round_size - i - 1) as f32).powi(2)) - .sqrt() - .round() as usize - } else { - 0 - } - } else { - 0 - }; - - // Top line - if border.2.contains(Sides::TOP) && canvas.width > rounding_space * 2 { - Line::new( - (self.pos.0 + rounding_space, self.pos.1 + i), - (self.pos.0 + self.size.0 - rounding_space, self.pos.1 + i), - border.1, - false, - ) - .draw(canvas); - } - // Bottom line - if border.2.contains(Sides::BOTTOM) && canvas.width > rounding_space * 2 { - Line::new( - (self.pos.0 + rounding_space, self.pos.1 + self.size.1 - i), - ( - self.pos.0 + self.size.0 - rounding_space, - self.pos.1 + self.size.1 - i, - ), - border.1, - false, - ) - .draw(canvas); - } - // Left line - if border.2.contains(Sides::LEFT) && canvas.height > rounding_space * 2 { - Line::new( - (self.pos.0 + i, self.pos.1 + rounding_space), - (self.pos.0 + i, self.pos.1 + self.size.1 - rounding_space), - border.1, - false, - ) - .draw(canvas); - } - // Right line - if border.2.contains(Sides::RIGHT) && canvas.height > rounding_space * 2 { - Line::new( - (self.pos.0 + self.size.0 - i, self.pos.1 + rounding_space), - ( - self.pos.0 + self.size.0 - i, - self.pos.1 + self.size.1 - rounding_space, - ), - border.1, - false, - ) - .draw(canvas); - } - } - } - } - - fn draw_area(&self, canvas: &mut Canvas) { - if let Some(fill) = self.fill { - let (area_pos, area_size) = self.measure_area(); - for y in area_pos.1..area_pos.1 + area_size.1 + 1 { - Line::new((area_pos.0, y), (area_pos.0 + area_size.0, y), fill, false).draw(canvas) - } - } - } - - fn measure_area(&self) -> ((usize, usize), (usize, usize)) { - let (mut area_pos, mut area_size) = (self.pos, self.size); - if let Some(border) = self.border { - if border.2.contains(Sides::TOP) { - area_pos.1 += border.0; - area_size.1 -= border.0; - } - if border.2.contains(Sides::BOTTOM) { - area_size.1 -= border.0; - } - if border.2.contains(Sides::LEFT) { - area_pos.0 += border.0; - area_size.0 -= border.0; - } - if border.2.contains(Sides::RIGHT) { - area_size.0 -= border.0; - } - } - (area_pos, area_size) - } -} - -impl Drawable for Rectangle { - fn draw(&self, canvas: &mut Canvas) { - self.draw_borders(canvas); - self.draw_area(canvas); - } -} diff --git a/third_party/cargo/vendor/andrew-0.2.1/src/text/mod.rs b/third_party/cargo/vendor/andrew-0.2.1/src/text/mod.rs deleted file mode 100644 index 7849fe8..0000000 --- a/third_party/cargo/vendor/andrew-0.2.1/src/text/mod.rs +++ /dev/null @@ -1,121 +0,0 @@ -/// A module that contains functions and objects relating to fontconfig -pub mod fontconfig; - -use rusttype::{point, Font, Scale, SharedBytes, VMetrics}; -use std::fs::File; -use std::io::Read; -use std::path::PathBuf; -use Canvas; -use Drawable; - -/// A drawable object that represents text -pub struct Text<'a> { - /// The position of the text on the canvas - pub pos: (usize, usize), - /// The color of the text - pub color: [u8; 4], - /// The text that is rendered to the canvas on draw - pub text: String, - /// The font used in rendering the text - pub font: Font<'a>, - /// The scale that is applied to the text - pub scale: Scale, - /// The vertical metrics of the text - pub v_metrics: VMetrics, -} - -/// Loads a font file into a `Vec` -pub fn load_font_file>(path: P) -> Vec { - let mut data: Vec = Vec::new(); - let mut file = File::open(path.into()).expect("Could not open font file"); - file.read_to_end(&mut data) - .expect("Could not read font file"); - data -} - -impl<'a> Text<'a> { - /// Creates a new Text object - pub fn new>, T: Into>( - pos: (usize, usize), - color: [u8; 4], - font_data: P, - height: f32, - width_scale: f32, - text: T, - ) -> Text<'a> { - let text = text.into(); - // Create font - let font = Font::from_bytes(font_data).expect("Error constructing Font"); - // Create scale - let scale = Scale { - x: height * width_scale, - y: height, - }; - // Create needed metrics - let v_metrics = font.v_metrics(scale); - Text { - pos, - color, - text: text.clone(), - scale, - v_metrics, - font, - } - } - - fn draw_text(&self, canvas: &mut Canvas) { - let glyphs: Vec<_> = self - .font - .layout(&self.text, self.scale, point(0.0, self.v_metrics.ascent)) - .collect(); - for glyph in glyphs { - if let Some(bounding_box) = glyph.pixel_bounding_box() { - glyph.draw(|x, y, v| { - let x = ((x as usize + self.pos.0) as i32 + bounding_box.min.x) as usize; - let y = ((y as usize + self.pos.1) as i32 + bounding_box.min.y) as usize; - - if x < canvas.width && y < canvas.height { - let mut color = self.color; - color[0] = (f32::from(color[0]) * v) as u8; - canvas.draw_point(x, y, color); - } - }); - } - } - } - - /// Calculates the width in pixels of the text - pub fn get_width(&self) -> usize { - let glyphs: Vec<_> = self - .font - .layout(&self.text, self.scale, point(0.0, self.v_metrics.ascent)) - .collect(); - let min_x = glyphs - .first() - .map(|g| { - if let Some(bb) = g.pixel_bounding_box() { - bb.min.x - } else { - g.position().x as i32 - } - }) - .unwrap_or(0); - let max_x = glyphs - .last() - .map(|g| { - if let Some(bb) = g.pixel_bounding_box() { - bb.max.x - } else { - (g.position().x + g.unpositioned().h_metrics().advance_width) as i32 - } - }) - .unwrap_or(0); - (max_x - min_x) as usize - } -} - -impl<'a> Drawable for Text<'a> { - fn draw(&self, canvas: &mut Canvas) { - self.draw_text(canvas); - } -} diff --git a/third_party/cargo/vendor/andrew-0.3.1/.cargo-checksum.json b/third_party/cargo/vendor/andrew-0.3.1/.cargo-checksum.json new file mode 100644 index 0000000..88118b3 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"2d031d89de7918f60e866fbdb1069a8e927112e817f384990dfe50873578e7d7","Cargo.lock":"faa3eeb18c2fab92248ac415c6e4c056e443779b58ba8bea86076c4132755e47","Cargo.toml":"aa8de0b7b23e0cb281a6bbcd1652964b70129a6a8f34f5313aa54264a25b8229","LICENSE":"0dd39f89842df915b8ded7ac59e8a1372cf5be36133818866cca2ef3af1a2849","README.md":"54274cb43d69009c72c8d28647ba28bc33f639bb0e81fb4fa8ace6ffc6c66bc2","doc_index.html":"284a4836b0eef54a3d8307e490d466fa9b1b749884fb88cf097e7cbbffb75590","examples/test.rs":"dafef175db24c64037a36397dccb0ba6879e6abb08befdb56d2fb5af47f7ffe1","src/lib.rs":"821bccf3441e41c4e55a6991d47a998c712e0a2f5ca6595752b005cbb453c3f3","src/line.rs":"cb3d3ea7938a74c169ce9c5b43111fe2793936324b499767affaf7e6c6340cf9","src/shapes/mod.rs":"071d6ea4080dc8f1e4299258d65c32bccc40e9eb6933f3b3600576d58e7917ae","src/shapes/rectangle.rs":"66b92e36d3e1df73facc5d8d37db962cb2a8d68a7e66ae6be0af9eab621ed917","src/text/fontconfig.rs":"c673bfcf5df387479dd2027a733d8de85461731b448202f49a9f2d1bce54f465","src/text/mod.rs":"4ce335cac3776b9a593989c30ffdc18b53bb14e2ab70d21eeacbb3bc710ac8cf"},"package":"8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf"} \ No newline at end of file diff --git a/third_party/cargo/vendor/andrew-0.3.1/BUILD.bazel b/third_party/cargo/vendor/andrew-0.3.1/BUILD.bazel new file mode 100644 index 0000000..7f5dbc6 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/BUILD.bazel @@ -0,0 +1,60 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT" +]) + +# Generated Targets + +# Unsupported target "test" with type "example" omitted + +rust_library( + name = "andrew", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.3.1", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/rusttype-0.9.2:rusttype", + "//third_party/cargo/vendor/walkdir-2.3.1:walkdir", + "//third_party/cargo/vendor/xdg-2.2.0:xdg", + "//third_party/cargo/vendor/xml-rs-0.8.3:xml_rs", + ], +) diff --git a/third_party/cargo/vendor/andrew-0.3.1/CHANGELOG.md b/third_party/cargo/vendor/andrew-0.3.1/CHANGELOG.md new file mode 100644 index 0000000..b69f441 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/CHANGELOG.md @@ -0,0 +1,58 @@ +# Change Log + +## Unreleased + +## 0.3.1 -- 2020-10-23 + +- Speed up rectangle drawing +- Remove dependency on line_drawing +- Update sctk dev dependency to 0.12 + +## 0.3.0 -- 2020-05-27 + +- Raised MSRV to `1.41.0`. +- Upgraded dependency versions. + +## 0.2.1 -- 2019-03-29 + +- Fix `get_width()` for texts that start and end with spaces + +## 0.2.0 -- 2019-01-26 + +- **[Breaking]** Canvas is now endian aware and will draw to the buffer in the endianness of the `Endian` its created with + +## 0.1.6 -- 2019-01-24 + +- Faster drawing of horizontal and verticle lines by precomputing line boundaries +- Only calculate alpha overlay when drawing colors without a non-max alpha value for performance + +## 0.1.5 -- 2019-01-13 + +- Fix drawing of characters with negative bounding boxes +- Fix error in `get_width()` for text without any characters + +## 0.1.4 -- 2018-11-10 + +- Remove rusttype version restriction + +## 0.1.3 -- 2018-10-09 + +- Move from `quick-xml` to `xml-rs` dependency + +## 0.1.2 -- 2018-10-04 + +- Add basic/experimental support for fontconfig in `andrew::text::fontconfig` + +## 0.1.1 -- 2018-09-17 + +- Manage dependencies to maintain rust 1.22 compatibility +- Update rusttype to 0.7.1 + +## 0.1.0 -- 2018-08-17 + +Initial version, including: + +- canvas +- lines +- rectangles +- text diff --git a/third_party/cargo/vendor/andrew-0.3.1/Cargo.lock b/third_party/cargo/vendor/andrew-0.3.1/Cargo.lock new file mode 100644 index 0000000..bd3e3e7 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/Cargo.lock @@ -0,0 +1,419 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff" + +[[package]] +name = "andrew" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1ea80a5089cac999ffd4a91888154076a961d27387b0f7a6cd2d4dddb636b9" +dependencies = [ + "bitflags", + "line_drawing", + "rusttype", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "andrew" +version = "0.3.1" +dependencies = [ + "bitflags", + "rusttype", + "smithay-client-toolkit", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "calloop" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" +dependencies = [ + "log", + "nix", +] + +[[package]] +name = "cc" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "dlib" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" + +[[package]] +name = "libloading" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557c9384f7f757f6d139cd3a4c62ef4e850696c16bf27924a5538c8a09717a1" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "line_drawing" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81902e542483002b103c6424d23e765c2e5a65f732923299053a601bce50ab2" +dependencies = [ + "num-traits 0.1.43", +] + +[[package]] +name = "log" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.12", +] + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" + +[[package]] +name = "owned_ttf_parser" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rusttype" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "smallvec" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" + +[[package]] +name = "smithay-client-toolkit" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec5c077def8af49f9b5aeeb5fcf8079c638c6615c3a8f9305e2dea601de57f7" +dependencies = [ + "andrew 0.3.0", + "bitflags", + "byteorder", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap", + "nix", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "ttf-parser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wayland-client" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80c54f9b90b2c044784f91fe22c5619a8a9c681db38492f2fd78ff968cf3f184" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7602d75560fe6f02cac723609cce658042fe60541b5107999818d29d4dab7cfa" +dependencies = [ + "nix", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0446b959c5b5b4b2c11f63112fc7cbeb50ecd9f2c340d2b0ea632875685baf04" +dependencies = [ + "nix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d419585bbdb150fb541579cff205c6095a86cd874530e41838d1f18a9569a08" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cc091af4b05a435312f7cefe3a26824d2017966a58362ca913f72c3d68e5e2" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5640f53d1fe6eaaa2e77b9ff015fe9a556173ce8388607f941aecfd9b05c73e" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xcursor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a481cfdefd35e1c50073ae33a8000d695c98039544659f5dc5dd71311b0d01" +dependencies = [ + "nom", +] + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" + +[[package]] +name = "xml-rs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" diff --git a/third_party/cargo/vendor/andrew-0.3.1/Cargo.toml b/third_party/cargo/vendor/andrew-0.3.1/Cargo.toml new file mode 100644 index 0000000..97f54a5 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "andrew" +version = "0.3.1" +authors = ["Lucas Timmins "] +description = "The andrew crate provides convenient drawing of objects such as shapes, lines and text to buffers" +readme = "README.md" +keywords = ["draw", "buffer", "shapes", "lines", "pixels"] +categories = ["rendering", "multimedia::images"] +license = "MIT" +repository = "https://github.com/Smithay/andrew" +[dependencies.bitflags] +version = "1.2.1" + +[dependencies.rusttype] +version = "0.9.2" + +[dependencies.walkdir] +version = "2.3.1" + +[dependencies.xdg] +version = "2.2.0" + +[dependencies.xml-rs] +version = "0.8.3" +[dev-dependencies.smithay-client-toolkit] +version = "0.12" diff --git a/third_party/cargo/vendor/andrew-0.2.1/LICENSE b/third_party/cargo/vendor/andrew-0.3.1/LICENSE similarity index 100% rename from third_party/cargo/vendor/andrew-0.2.1/LICENSE rename to third_party/cargo/vendor/andrew-0.3.1/LICENSE diff --git a/third_party/cargo/vendor/andrew-0.3.1/README.md b/third_party/cargo/vendor/andrew-0.3.1/README.md new file mode 100644 index 0000000..794eac7 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/README.md @@ -0,0 +1,13 @@ +[![crates.io](http://meritbadge.herokuapp.com/andrew)](https://crates.io/crates/andrew) +[![Build Status](https://travis-ci.org/Smithay/andrew.svg?branch=master)](https://travis-ci.org/Smithay/andrew) +[![Docs Status](https://docs.rs/andrew/badge.svg)](https://docs.rs/andrew) + +# Andrew + +This crate provides convenient drawing of objects such as shapes, lines and text to buffers + +## Documentation + +The documentation for the master branch is [available online](https://smithay.github.io/andrew/). + +The documentation for the releases can be found on [docs.rs](https://docs.rs/andrew). diff --git a/third_party/cargo/vendor/andrew-0.3.1/doc_index.html b/third_party/cargo/vendor/andrew-0.3.1/doc_index.html new file mode 100644 index 0000000..1f27c24 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/doc_index.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/third_party/cargo/vendor/andrew-0.3.1/examples/test.rs b/third_party/cargo/vendor/andrew-0.3.1/examples/test.rs new file mode 100644 index 0000000..da88176 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/examples/test.rs @@ -0,0 +1,206 @@ +extern crate andrew; +extern crate smithay_client_toolkit as sctk; + +use std::io::{Read, Seek, SeekFrom, Write}; +use std::time::{Duration, Instant}; + +use sctk::reexports::client::protocol::{wl_seat::WlSeat, wl_shm, wl_surface}; +use sctk::shm::{DoubleMemPool, MemPool}; +use sctk::window::{ConceptFrame, Event as WEvent}; + +use andrew::shapes::rectangle; +use andrew::text; +use andrew::text::fontconfig; + +sctk::default_environment!(TestExample, desktop); + +fn main() { + let (env, display, mut event_queue) = sctk::new_default_environment!(TestExample, desktop) + .expect("Unable to connect to a Wayland compositor"); + + let _seat = env.manager.instantiate_range::(1, 6).unwrap(); + + let mut dimensions = (600, 400); + let surface = env.create_surface().detach(); + let mut next_action = None::; + + let mut window = env + .create_window::(surface, None, dimensions, move |evt, mut dispatch_data| { + let next_actn = dispatch_data.get::>().unwrap(); + // Keep last event in priority order : Close > Configure > Refresh + let replace = match (&evt, &*next_actn) { + (_, &None) + | (_, &Some(WEvent::Refresh)) + | (&WEvent::Configure { .. }, &Some(WEvent::Configure { .. })) + | (&WEvent::Close, _) => true, + _ => false, + }; + if replace { + *next_actn = Some(evt); + } + }) + .expect("Failed to create a window !"); + + let mut pools = DoubleMemPool::new( + env.get_global().expect("Failed to get `WlShm` global."), + |_| {}, + ) + .expect("Failed to create a memory pool !"); + + let mut font_data = Vec::new(); + ::std::fs::File::open( + &fontconfig::FontConfig::new() + .unwrap() + .get_regular_family_fonts("sans") + .unwrap()[0], + ) + .unwrap() + .read_to_end(&mut font_data) + .unwrap(); + + if !env + .get_shell() + .expect("Expected environment to contain a shell.") + .needs_configure() + { + if let Some(pool) = pools.pool() { + redraw(pool, window.surface(), dimensions, &font_data); + } + window.refresh(); + } + + loop { + match next_action.take() { + Some(WEvent::Close) => break, + Some(WEvent::Refresh) => { + window.refresh(); + window.surface().commit(); + } + Some(WEvent::Configure { new_size, .. }) => { + if let Some((w, h)) = new_size { + window.resize(w, h); + dimensions = (w, h) + } + window.refresh(); + if let Some(pool) = pools.pool() { + redraw(pool, window.surface(), dimensions, &font_data); + } + } + None => {} + } + + display.flush().unwrap(); + event_queue + .dispatch(&mut next_action, |_, _, _| {}) + .unwrap(); + } +} + +fn redraw( + pool: &mut MemPool, + surface: &wl_surface::WlSurface, + dimensions: (u32, u32), + font_data: &[u8], +) { + let (buf_x, buf_y) = (dimensions.0 as usize, dimensions.1 as usize); + + pool.resize(4 * buf_x * buf_y) + .expect("Failed to resize the memory pool."); + + let mut buf: Vec = vec![255; 4 * buf_x * buf_y]; + let mut canvas = + andrew::Canvas::new(&mut buf, buf_x, buf_y, 4 * buf_x, andrew::Endian::native()); + + println!("______________"); + let mut total_dur = Duration::new(0, 0); + + // Draw background + let (block_w, block_h) = (buf_x / 20, buf_y / 20); + for block_y in 0..21 { + for block_x in 0..21 { + let color = if (block_x + (block_y % 2)) % 2 == 0 { + [255, 0, 0, 0] + } else { + [255, 255, 255, 255] + }; + + let block = rectangle::Rectangle::new( + (block_w * block_x, block_h * block_y), + (block_w, block_h), + None, + Some(color), + ); + let timer = Instant::now(); + canvas.draw(&block); + total_dur += timer.elapsed() + } + } + println!("Background draw time: {:?}", total_dur); + + let rectangle = rectangle::Rectangle::new( + (buf_x / 30, buf_y / 4), + (buf_x - (buf_x / 30) * 2, buf_y - buf_y / 2), + Some(( + 15, + [255, 170, 20, 45], + rectangle::Sides::TOP ^ rectangle::Sides::BOTTOM, + Some(10), + )), + Some([255, 170, 20, 45]), + ); + let mut timer = Instant::now(); + canvas.draw(&rectangle); + println!("Rectangle draw time: {:?}", timer.elapsed()); + total_dur += timer.elapsed(); + + let text_h = buf_x as f32 / 80.; + let text_hh = text_h / 2.; + let mut text = text::Text::new( + (63, 69), + [255, 255, 255, 255], + font_data, + text_h, + 2.0, + "“Life is the art of drawing without an eraser.” - John W. Gardner", + ); + text.pos = ( + buf_x / 2 - text.get_width() / 2, + buf_y / 2 - text_hh as usize, + ); + + let text_box = rectangle::Rectangle::new( + ( + buf_x / 2 - text.get_width() / 2 - 10, + buf_y / 2 - text_hh as usize - 10, + ), + (text.get_width() + 20, text_h as usize + 20), + Some((3, [255, 255, 255, 255], rectangle::Sides::ALL, Some(5))), + None, + ); + + timer = Instant::now(); + canvas.draw(&text_box); + println!("Text box draw time: {:?}", timer.elapsed()); + total_dur += timer.elapsed(); + + timer = Instant::now(); + canvas.draw(&text); + println!("Text draw time: {:?}", timer.elapsed()); + total_dur += timer.elapsed(); + + println!("Total draw time: {:?}", total_dur); + + pool.seek(SeekFrom::Start(0)).unwrap(); + pool.write_all(canvas.buffer).unwrap(); + pool.flush().unwrap(); + + let new_buffer = pool.buffer( + 0, + buf_x as i32, + buf_y as i32, + 4 * buf_x as i32, + wl_shm::Format::Argb8888, + ); + surface.attach(Some(&new_buffer), 0, 0); + surface.commit(); +} diff --git a/third_party/cargo/vendor/andrew-0.3.1/src/lib.rs b/third_party/cargo/vendor/andrew-0.3.1/src/lib.rs new file mode 100644 index 0000000..9bf1ded --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/src/lib.rs @@ -0,0 +1,133 @@ +//! Andrew is a crate for drawing objects +#![warn(missing_docs)] +extern crate rusttype; +extern crate walkdir; +extern crate xdg; +extern crate xml; + +#[macro_use] +extern crate bitflags; + +/// A module that contains functions and objects relating to lines +pub mod line; +/// A module that contains functions and objects relating to shapes +pub mod shapes; +/// A module that contains functions and objects relating to text +pub mod text; + +/// The Drawable trait allows object to be drawn to a buffer or canvas +pub trait Drawable { + /// A function that draws the object to a canvas + fn draw(&self, canvas: &mut Canvas); +} + +/// Describes an endianness (aka byte order) +#[derive(Debug, PartialEq)] +pub enum Endian { + /// Little Endian + Little, + /// Big Endian + Big, +} + +impl Endian { + /// Returns the native endianness + pub fn native() -> Endian { + if cfg!(target_endian = "little") { + Endian::Little + } else { + Endian::Big + } + } +} + +/// The canvas object acts as a wrapper around a buffer, providing information and functions +/// for drawing +pub struct Canvas<'a> { + /// A buffer for the canvas to draw to + pub buffer: &'a mut [u8], + /// The width in pixels of the canvas + pub width: usize, + /// The height in pixels of the canvas + pub height: usize, + /// The number of bytes between each line of pixels on the canvas + pub stride: usize, + /// The number of bytes contained in each pixel + pub pixel_size: usize, + /// The endianness of the canvas + pub endianness: Endian, +} + +impl<'a> Canvas<'a> { + /// Creates a new canvas object + pub fn new( + buffer: &'a mut [u8], + width: usize, + height: usize, + stride: usize, + endianness: Endian, + ) -> Canvas<'a> { + assert!( + stride % width == 0, + "Incorrect Dimensions - Stride is not a multiple of width" + ); + assert!(buffer.len() == stride * height); + let pixel_size = stride / width; + Canvas { + buffer, + width, + height, + stride, + pixel_size, + endianness, + } + } + + /// Draws an object that implements the Drawable trait to the buffer + pub fn draw(&mut self, drawable: &D) { + drawable.draw(self); + } + + /// Draws a pixel at the x and y coordinate + pub fn draw_point(&mut self, x: usize, y: usize, color: [u8; 4]) { + let base = self.stride * y + self.pixel_size * x; + if self.endianness == Endian::Little { + if color[0] == 255 { + self.buffer[base + 3] = color[0]; + self.buffer[base + 2] = color[1]; + self.buffer[base + 1] = color[2]; + self.buffer[base] = color[3]; + } else { + for c in 0..3 { + let alpha = f32::from(color[0]) / 255.0; + let color_diff = + (color[3 - c] as isize - self.buffer[base + c] as isize) as f32 * alpha; + let new_color = (f32::from(self.buffer[base + c]) + color_diff) as u8; + self.buffer[base + c] = new_color as u8; + } + self.buffer[base + 3] = 255 as u8; + } + } else if color[0] == 255 { + self.buffer[base] = color[0]; + self.buffer[base + 1] = color[1]; + self.buffer[base + 2] = color[2]; + self.buffer[base + 3] = color[3]; + } else { + for c in 1..4 { + let alpha = f32::from(color[0]) / 255.0; + let color_diff = + (color[c] as isize - self.buffer[base + c] as isize) as f32 * alpha; + let new_color = (f32::from(self.buffer[base + c]) + color_diff) as u8; + self.buffer[base + c] = new_color as u8; + } + self.buffer[base] = 255 as u8; + } + } + + /// Clears the entire canvas buffer by zeroing it + pub fn clear(&mut self) { + for i in 0..self.width * self.height * 4 { + self.buffer[i] = 0x00; + } + } +} diff --git a/third_party/cargo/vendor/andrew-0.3.1/src/line.rs b/third_party/cargo/vendor/andrew-0.3.1/src/line.rs new file mode 100644 index 0000000..1fda80c --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/src/line.rs @@ -0,0 +1,167 @@ +use std::cmp::{max, min}; + +use Canvas; +use Drawable; +use Endian; + +/// A drawable object that represents a line +pub struct Line { + /// The first point of the line + pub pt1: (usize, usize), + /// The second point of the line + pub pt2: (usize, usize), + /// The color of the line + pub color: [u8; 4], + /// Decides whether the line will be antialiased + pub antialiased: bool, +} + +impl Line { + /// Creates a new Line object + pub fn new( + pt1: (usize, usize), + pt2: (usize, usize), + color: [u8; 4], + antialiased: bool, + ) -> Line { + Line { + pt1, + pt2, + color, + antialiased, + } + } +} + +impl Drawable for Line { + fn draw(&self, canvas: &mut Canvas) { + if !self.antialiased { + if self.pt1.0 == self.pt2.0 && self.pt1.0 < canvas.width { + let min_y = min(self.pt1.1, self.pt2.1); + let max_y = min(max(self.pt1.1, self.pt2.1), canvas.height - 1); + for y in min_y..=max_y { + canvas.draw_point(self.pt1.0, y, self.color) + } + } else if self.pt1.1 == self.pt2.1 && self.pt1.1 < canvas.height { + let min_x = min(self.pt1.0, self.pt2.0); + let max_x = min(max(self.pt1.0, self.pt2.0), canvas.width - 1); + for x in min_x..=max_x { + canvas.draw_point(x, self.pt1.1, self.color) + } + } else { + // Angled line without antialias + for (x, y) in bresenham( + self.pt1.0 as isize, + self.pt1.1 as isize, + self.pt2.0 as isize, + self.pt2.1 as isize, + ) { + if x < canvas.width && y < canvas.height { + canvas.draw_point(x, y, self.color) + } + } + } + } else { + // Angled line with antialias + for (x, y, coverage) in xiaolin_wu( + self.pt1.0 as f32, + self.pt1.1 as f32, + self.pt2.0 as f32, + self.pt2.1 as f32, + ) { + if x < canvas.width && y < canvas.height { + let mut color = self.color; + let base = canvas.stride * y + canvas.pixel_size * x; + if coverage != 1.0 { + if canvas.endianness == Endian::Little { + color[1] = (canvas.buffer[base + 2] as f32 * (1.0 - coverage) + + color[1] as f32 * coverage) + as u8; + color[2] = (canvas.buffer[base + 1] as f32 * (1.0 - coverage) + + color[2] as f32 * coverage) + as u8; + color[3] = (canvas.buffer[base] as f32 * (1.0 - coverage) + + color[3] as f32 * coverage) + as u8; + } else { + color[1] = (canvas.buffer[base + 1] as f32 * (1.0 - coverage) + + color[1] as f32 * coverage) + as u8; + color[2] = (canvas.buffer[base + 2] as f32 * (1.0 - coverage) + + color[2] as f32 * coverage) + as u8; + color[3] = (canvas.buffer[base + 3] as f32 * (1.0 - coverage) + + color[3] as f32 * coverage) + as u8; + } + } + canvas.draw_point(x as usize, y as usize, color) + } + } + } + } +} + +fn bresenham(mut x0: isize, mut y0: isize, x1: isize, y1: isize) -> Vec<(usize, usize)> { + let mut points: Vec<(usize, usize)> = Vec::new(); + let dx = (x1 - x0).abs(); + let sx = if x0 < x1 { 1 } else { -1 }; + let dy = -((y1 - y0).abs()); + let sy = if y0 < y1 { 1 } else { -1 }; + let mut err = dx + dy; + + loop { + points.push((x0 as usize, y0 as usize)); + if x0 == x1 && y0 == y1 { + break; + }; + let e2 = 2 * err; + if e2 >= dy { + err += dy; + x0 += sx; + } + if e2 <= dx { + err += dx; + y0 += sy; + } + } + points +} + +fn xiaolin_wu(mut x0: f32, mut y0: f32, mut x1: f32, mut y1: f32) -> Vec<(usize, usize, f32)> { + let mut points: Vec<(usize, usize, f32)> = Vec::new(); + let steep = (y1 - y0).abs() > (x1 - x0).abs(); + if steep { + std::mem::swap(&mut x0, &mut y0); + std::mem::swap(&mut x1, &mut y1); + } + if x0 > x1 { + std::mem::swap(&mut x0, &mut x1); + std::mem::swap(&mut y0, &mut y1); + } + let dx = x1 - x0; + let dy = y1 - y0; + let gradient = if dx == 0.0 { + 1.0 + } else { + dy as f32 / dx as f32 + }; + + let mut intery = y0 + gradient; + points.push((x0 as usize, y0 as usize, 1.0)); + points.push((x1 as usize, y1 as usize, 1.0)); + if steep { + for x in x0 as usize + 1..=x1 as usize - 1 { + points.push((intery as usize, x, 1.0 - intery.fract())); + points.push((intery as usize + 1, x, intery.fract())); + intery = intery + gradient; + } + } else { + for x in x0 as usize + 1..=x1 as usize - 1 { + points.push((x, intery as usize, 1.0 - intery.fract())); + points.push((x, intery as usize + 1, intery.fract())); + intery = intery + gradient; + } + } + points +} diff --git a/third_party/cargo/vendor/andrew-0.2.1/src/shapes/mod.rs b/third_party/cargo/vendor/andrew-0.3.1/src/shapes/mod.rs similarity index 100% rename from third_party/cargo/vendor/andrew-0.2.1/src/shapes/mod.rs rename to third_party/cargo/vendor/andrew-0.3.1/src/shapes/mod.rs diff --git a/third_party/cargo/vendor/andrew-0.3.1/src/shapes/rectangle.rs b/third_party/cargo/vendor/andrew-0.3.1/src/shapes/rectangle.rs new file mode 100644 index 0000000..8ed7522 --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/src/shapes/rectangle.rs @@ -0,0 +1,166 @@ +use std::cmp::min; + +use Canvas; +use Drawable; + +bitflags! { + /// The Sides bitflag presents the sides of a rectangle + pub struct Sides: u32 { + /// The top side of the rectangle + const TOP = 0b0001; + /// The bottom side of the rectangle + const BOTTOM = 0b0010; + /// The left side of the rectangle + const LEFT = 0b0100; + /// The right side of the rectangle + const RIGHT = 0b1000; + /// All sides of the rectangle + const ALL = Self::TOP.bits | Self::BOTTOM.bits | Self::LEFT.bits | Self::RIGHT.bits; + } +} + +/// A drawable object that represents a rectangle +pub struct Rectangle { + /// Position of the top-left corner of rectangle + pub pos: (usize, usize), + /// The size of the rectangle to be drawn, the border will be contained within this size + pub size: (usize, usize), + /// The border that is drawn around the perimeter of the rectangle. It's arguments are + /// thickness of border, color of border, sides that the border is drawn around, rounding size + /// of the corners + pub border: Option<(usize, [u8; 4], Sides, Option)>, + /// The color of the fill (area) of the rectangle + pub fill: Option<[u8; 4]>, +} + +impl Rectangle { + /// Creates a new Rectangle object + pub fn new( + pos: (usize, usize), + size: (usize, usize), + border: Option<(usize, [u8; 4], Sides, Option)>, + fill: Option<[u8; 4]>, + ) -> Rectangle { + Rectangle { + pos, + size, + border, + fill, + } + } + + fn draw_borders(&self, canvas: &mut Canvas) { + if let Some(border) = self.border { + for i in 0..=border.0 { + let rounding_space = if let Some(round_size) = border.3 { + if i < round_size { + round_size + - ((round_size as f32).powi(2) - ((round_size - i - 1) as f32).powi(2)) + .sqrt() + .round() as usize + } else { + 0 + } + } else { + 0 + }; + + // Top line + if border.2.contains(Sides::TOP) + && canvas.width > rounding_space * 2 + && self.pos.1 + i <= canvas.height - 1 + { + for x in self.pos.0 + rounding_space + ..=min( + self.pos.0 + self.size.0 - rounding_space - 1, + canvas.width - 1, + ) + { + canvas.draw_point(x, self.pos.1 + i, border.1) + } + } + // Bottom line + if border.2.contains(Sides::BOTTOM) + && canvas.width > rounding_space * 2 + && self.pos.1 + self.size.1 - i - 1 <= canvas.height - 1 + { + for x in self.pos.0 + rounding_space + ..=min( + self.pos.0 + self.size.0 - rounding_space - 1, + canvas.width - 1, + ) + { + canvas.draw_point(x, self.pos.1 + self.size.1 - i - 1, border.1) + } + } + // Left line + if border.2.contains(Sides::LEFT) + && canvas.height > rounding_space * 2 + && self.pos.0 + i <= canvas.width - 1 + { + for y in self.pos.1 + rounding_space + ..=min( + self.pos.1 + self.size.1 - rounding_space - 1, + canvas.height - 1, + ) + { + canvas.draw_point(self.pos.0 + i, y, border.1) + } + } + // Right line + if border.2.contains(Sides::RIGHT) + && canvas.height > rounding_space * 2 + && self.pos.0 + self.size.0 - i - 1 <= canvas.width - 1 + { + for y in self.pos.1 + rounding_space + ..=min( + self.pos.1 + self.size.1 - rounding_space - 1, + canvas.height - 1, + ) + { + canvas.draw_point(self.pos.0 + self.size.0 - i - 1, y, border.1) + } + } + } + } + } + + fn draw_area(&self, canvas: &mut Canvas) { + if let Some(fill) = self.fill { + let (area_pos, area_size) = self.measure_area(); + for y in area_pos.1..=min(area_pos.1 + area_size.1 - 1, canvas.height - 1) { + for x in area_pos.0..=min(area_pos.0 + area_size.0 - 1, canvas.width - 1) { + canvas.draw_point(x, y, fill) + } + } + } + } + + fn measure_area(&self) -> ((usize, usize), (usize, usize)) { + let (mut area_pos, mut area_size) = (self.pos, self.size); + if let Some(border) = self.border { + if border.2.contains(Sides::TOP) { + area_pos.1 += border.0; + area_size.1 -= border.0; + } + if border.2.contains(Sides::BOTTOM) { + area_size.1 -= border.0; + } + if border.2.contains(Sides::LEFT) { + area_pos.0 += border.0; + area_size.0 -= border.0; + } + if border.2.contains(Sides::RIGHT) { + area_size.0 -= border.0; + } + } + (area_pos, area_size) + } +} + +impl Drawable for Rectangle { + fn draw(&self, canvas: &mut Canvas) { + self.draw_borders(canvas); + self.draw_area(canvas); + } +} diff --git a/third_party/cargo/vendor/andrew-0.2.1/src/text/fontconfig.rs b/third_party/cargo/vendor/andrew-0.3.1/src/text/fontconfig.rs similarity index 100% rename from third_party/cargo/vendor/andrew-0.2.1/src/text/fontconfig.rs rename to third_party/cargo/vendor/andrew-0.3.1/src/text/fontconfig.rs diff --git a/third_party/cargo/vendor/andrew-0.3.1/src/text/mod.rs b/third_party/cargo/vendor/andrew-0.3.1/src/text/mod.rs new file mode 100644 index 0000000..348048a --- /dev/null +++ b/third_party/cargo/vendor/andrew-0.3.1/src/text/mod.rs @@ -0,0 +1,121 @@ +/// A module that contains functions and objects relating to fontconfig +pub mod fontconfig; + +use rusttype::{point, Font, Scale, VMetrics}; +use std::fs::File; +use std::io::Read; +use std::path::PathBuf; +use Canvas; +use Drawable; + +/// A drawable object that represents text +pub struct Text<'a> { + /// The position of the text on the canvas + pub pos: (usize, usize), + /// The color of the text + pub color: [u8; 4], + /// The text that is rendered to the canvas on draw + pub text: String, + /// The font used in rendering the text + pub font: Font<'a>, + /// The scale that is applied to the text + pub scale: Scale, + /// The vertical metrics of the text + pub v_metrics: VMetrics, +} + +/// Loads a font file into a `Vec` +pub fn load_font_file>(path: P) -> Vec { + let mut data: Vec = Vec::new(); + let mut file = File::open(path.into()).expect("Could not open font file"); + file.read_to_end(&mut data) + .expect("Could not read font file"); + data +} + +impl<'a> Text<'a> { + /// Creates a new Text object + pub fn new>( + pos: (usize, usize), + color: [u8; 4], + font_data: &'a [u8], + height: f32, + width_scale: f32, + text: T, + ) -> Text<'a> { + let text = text.into(); + // Create font + let font = Font::try_from_bytes(font_data).expect("Error constructing Font"); + // Create scale + let scale = Scale { + x: height * width_scale, + y: height, + }; + // Create needed metrics + let v_metrics = font.v_metrics(scale); + Text { + pos, + color, + text: text.clone(), + scale, + v_metrics, + font, + } + } + + fn draw_text(&self, canvas: &mut Canvas) { + let glyphs: Vec<_> = self + .font + .layout(&self.text, self.scale, point(0.0, self.v_metrics.ascent)) + .collect(); + for glyph in glyphs { + if let Some(bounding_box) = glyph.pixel_bounding_box() { + glyph.draw(|x, y, v| { + let x = ((x as usize + self.pos.0) as i32 + bounding_box.min.x) as usize; + let y = ((y as usize + self.pos.1) as i32 + bounding_box.min.y) as usize; + + if x < canvas.width && y < canvas.height { + let mut color = self.color; + color[0] = (f32::from(color[0]) * v) as u8; + canvas.draw_point(x, y, color); + } + }); + } + } + } + + /// Calculates the width in pixels of the text + pub fn get_width(&self) -> usize { + let glyphs: Vec<_> = self + .font + .layout(&self.text, self.scale, point(0.0, self.v_metrics.ascent)) + .collect(); + let min_x = glyphs + .first() + .map(|g| { + if let Some(bb) = g.pixel_bounding_box() { + bb.min.x + } else { + g.position().x as i32 + } + }) + .unwrap_or(0); + let max_x = glyphs + .last() + .map(|g| { + if let Some(bb) = g.pixel_bounding_box() { + bb.max.x + } else { + (g.position().x + g.unpositioned().h_metrics().advance_width) as i32 + } + }) + .unwrap_or(0); + (max_x - min_x) as usize + } +} + +impl<'a> Drawable for Text<'a> { + fn draw(&self, canvas: &mut Canvas) { + self.draw_text(canvas); + } +} diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/.cargo-checksum.json b/third_party/cargo/vendor/android_log-sys-0.1.2/.cargo-checksum.json deleted file mode 100644 index 27a70aa..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"18788b5d8b84916aedc7c85961a8c99f748969e9562663dbfc9704d2263df23d","LICENSE-APACHE":"4d4c32b31308f5a992434c2cf948205852bb2c7bb85cea4c1ab051f41a3eefb3","LICENSE-MIT":"bb3c0c388d2e5efc777ee1a7bc4671188447d5fbbad130aecac9fd52e0010b76","README.md":"56808f9f272c6fad922f23033591464c1403bb5d1f716ee224b6933b90d62e86","src/lib.rs":"ff810c7e6fe722309ea46f9f2a87c10a857f7c6b3563a5986d2d235cdc2109e2"},"package":"b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e"} \ No newline at end of file diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/BUILD.bazel b/third_party/cargo/vendor/android_log-sys-0.1.2/BUILD.bazel deleted file mode 100644 index a1fb726..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/BUILD.bazel +++ /dev/null @@ -1,53 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "android_log_sys", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.1.2", - # buildifier: leave-alone - deps = [ - ], -) diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/Cargo.toml b/third_party/cargo/vendor/android_log-sys-0.1.2/Cargo.toml deleted file mode 100644 index 1391304..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "android_log-sys" -version = "0.1.2" -authors = ["Nerijus Arlauskas "] -description = "FFI bindings to Android log Library.\n" -documentation = "https://docs.rs/android_log-sys" -readme = "README.md" -keywords = ["ffi", "android", "log"] -categories = ["external-ffi-bindings"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/nercury/android_log-sys-rs" - -[lib] -name = "android_log_sys" diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/LICENSE-APACHE b/third_party/cargo/vendor/android_log-sys-0.1.2/LICENSE-APACHE deleted file mode 100644 index 09ed963..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "{}" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright 2016 The android_log_sys Developers - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/LICENSE-MIT b/third_party/cargo/vendor/android_log-sys-0.1.2/LICENSE-MIT deleted file mode 100644 index e09729e..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/LICENSE-MIT +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016 The android_log_sys Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/README.md b/third_party/cargo/vendor/android_log-sys-0.1.2/README.md deleted file mode 100644 index 88e9528..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Bindings to Android log Library - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/third_party/cargo/vendor/android_log-sys-0.1.2/src/lib.rs b/third_party/cargo/vendor/android_log-sys-0.1.2/src/lib.rs deleted file mode 100644 index 0ee0739..0000000 --- a/third_party/cargo/vendor/android_log-sys-0.1.2/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2016 The android_log_sys Developers -// -// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be -// copied, modified, or distributed except according to those terms. - -use std::os::raw; - -#[allow(non_camel_case_types)] -pub type c_va_list = raw::c_void; -#[allow(non_camel_case_types)] -pub type c_int = raw::c_int; -#[allow(non_camel_case_types)] -pub type c_char = raw::c_char; - -// automatically generated by rust-bindgen - -#[derive(Clone, Copy)] -#[repr(isize)] -pub enum LogPriority { - UNKNOWN = 0, - DEFAULT = 1, - VERBOSE = 2, - DEBUG = 3, - INFO = 4, - WARN = 5, - ERROR = 6, - FATAL = 7, - SILENT = 8, -} - -#[link(name = "log")] -extern "C" { - pub fn __android_log_write(prio: c_int, - tag: *const c_char, - text: *const c_char) - -> c_int; - pub fn __android_log_print(prio: c_int, - tag: *const c_char, - fmt: *const c_char, - ...) - -> c_int; - pub fn __android_log_vprint(prio: c_int, - tag: *const c_char, - fmt: *const c_char, - ap: *mut c_va_list) - -> c_int; - pub fn __android_log_assert(cond: *const c_char, - tag: *const c_char, - fmt: *const c_char, - ...); -} diff --git a/third_party/cargo/vendor/approx-0.3.2/.cargo-checksum.json b/third_party/cargo/vendor/approx-0.3.2/.cargo-checksum.json deleted file mode 100644 index a795193..0000000 --- a/third_party/cargo/vendor/approx-0.3.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"bcd8107c8c85e92fb0b291014b8ba62bb1f076ec297028fd44e264765c303f2f","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"5e965438ec90b7ede0a5c93c482a91536759c147e215f7471d8534f121feb244","src/abs_diff_eq.rs":"b11c8128d1460ee9739abeedc49d8923fde2acb953481661f5adc94feef86761","src/lib.rs":"075aa97495af343ad128b59cdec0206eb06d30d153abe1c38226d9d0f55c0fc9","src/macros.rs":"a9b59cce0cdb3e154321e7ba6ed2d53c21eeb8a46840a761e36e0259b44a59c4","src/relative_eq.rs":"ff292f125853ff846adc29cfa260042bab5e329e7b47b732e863587b8946b9d2","src/ulps_eq.rs":"21ad336b9ed8762eb3b7b1dd1b47b001edc8497d85c8c385bf8b2964be5687e7","tests/abs_diff_eq.rs":"9df9b48842dbc61b04b0328b64f2ce48b6e66e9538178babd58a9e52adeaddaf","tests/macro_import.rs":"006d813c99217d251a30b2f248548e7ad385754f88f6d9838d1dee866ea4b7f4","tests/macros.rs":"697241db4db66633cb53324bb127c64fd3b544236055bfe1721abb64a1dfab23","tests/relative_eq.rs":"c114edb6af07a2ac126e167682dd5d677d5591217f48bfdba150f866dfe4fdaf","tests/ulps_eq.rs":"ef6d57b98394fc87e724e26de7a3461426444563ec962661f660875b0702aeb6"},"package":"f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"} \ No newline at end of file diff --git a/third_party/cargo/vendor/approx-0.3.2/BUILD.bazel b/third_party/cargo/vendor/approx-0.3.2/BUILD.bazel deleted file mode 100644 index df4956a..0000000 --- a/third_party/cargo/vendor/approx-0.3.2/BUILD.bazel +++ /dev/null @@ -1,66 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # Apache-2.0 from expression "Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "approx", - srcs = glob(["**/*.rs"]), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.3.2", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/num-traits-0.2.11:num_traits", - ], -) - -# Unsupported target "abs_diff_eq" with type "test" omitted - -# Unsupported target "macro_import" with type "test" omitted - -# Unsupported target "macros" with type "test" omitted - -# Unsupported target "relative_eq" with type "test" omitted - -# Unsupported target "ulps_eq" with type "test" omitted diff --git a/third_party/cargo/vendor/approx-0.3.2/Cargo.toml b/third_party/cargo/vendor/approx-0.3.2/Cargo.toml deleted file mode 100644 index 5fc4d2d..0000000 --- a/third_party/cargo/vendor/approx-0.3.2/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "approx" -version = "0.3.2" -authors = ["Brendan Zabarauskas "] -description = "Approximate floating point equality comparisons and assertions." -homepage = "https://github.com/brendanzab/approx" -documentation = "https://docs.rs/approx" -readme = "README.md" -keywords = ["approximate", "assert", "comparison", "equality", "float"] -license = "Apache-2.0" -repository = "https://github.com/brendanzab/approx" -[package.metadata.docs.rs] -features = ["std", "num-complex"] - -[lib] -name = "approx" -[dependencies.num-complex] -version = "0.2.0" -optional = true - -[dependencies.num-traits] -version = "0.2.0" -default_features = false - -[features] -default = ["std"] -std = [] diff --git a/third_party/cargo/vendor/approx-0.3.2/src/lib.rs b/third_party/cargo/vendor/approx-0.3.2/src/lib.rs deleted file mode 100644 index a857f47..0000000 --- a/third_party/cargo/vendor/approx-0.3.2/src/lib.rs +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2015 Brendan Zabarauskas -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A crate that provides facilities for testing the approximate equality of floating-point -//! based types, using either relative difference, or units in the last place (ULPs) -//! comparisons. -//! -//! You can also use the `approx_{eq, ne}!` `assert_approx_{eq, ne}!` macros to test for equality -//! using a more positional style. -//! -//! ```rust -//! #[macro_use] -//! extern crate approx; -//! -//! use std::f64; -//! -//! # fn main() { -//! abs_diff_eq!(1.0, 1.0); -//! abs_diff_eq!(1.0, 1.0, epsilon = f64::EPSILON); -//! -//! relative_eq!(1.0, 1.0); -//! relative_eq!(1.0, 1.0, epsilon = f64::EPSILON); -//! relative_eq!(1.0, 1.0, max_relative = 1.0); -//! relative_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_relative = 1.0); -//! relative_eq!(1.0, 1.0, max_relative = 1.0, epsilon = f64::EPSILON); -//! -//! ulps_eq!(1.0, 1.0); -//! ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON); -//! ulps_eq!(1.0, 1.0, max_ulps = 4); -//! ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_ulps = 4); -//! ulps_eq!(1.0, 1.0, max_ulps = 4, epsilon = f64::EPSILON); -//! # } -//! ``` -//! -//! # Implementing approximate equality for custom types -//! -//! The `ApproxEq` trait allows approximate equalities to be implemented on types, based on the -//! fundamental floating point implementations. -//! -//! For example, we might want to be able to do approximate assertions on a complex number type: -//! -//! ```rust -//! #[macro_use] -//! extern crate approx; -//! # use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -//! -//! #[derive(Debug, PartialEq)] -//! struct Complex { -//! x: T, -//! i: T, -//! } -//! # impl AbsDiffEq for Complex where T::Epsilon: Copy { -//! # type Epsilon = T::Epsilon; -//! # fn default_epsilon() -> T::Epsilon { T::default_epsilon() } -//! # fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool { -//! # T::abs_diff_eq(&self.x, &other.x, epsilon) && -//! # T::abs_diff_eq(&self.i, &other.i, epsilon) -//! # } -//! # } -//! # impl RelativeEq for Complex where T::Epsilon: Copy { -//! # fn default_max_relative() -> T::Epsilon { T::default_max_relative() } -//! # fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -//! # -> bool { -//! # T::relative_eq(&self.x, &other.x, epsilon, max_relative) && -//! # T::relative_eq(&self.i, &other.i, epsilon, max_relative) -//! # } -//! # } -//! # impl UlpsEq for Complex where T::Epsilon: Copy { -//! # fn default_max_ulps() -> u32 { T::default_max_ulps() } -//! # fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool { -//! # T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) && -//! # T::ulps_eq(&self.i, &other.i, epsilon, max_ulps) -//! # } -//! # } -//! -//! # fn main() { -//! let x = Complex { x: 1.2, i: 2.3 }; -//! -//! assert_relative_eq!(x, x); -//! assert_ulps_eq!(x, x, max_ulps = 4); -//! # } -//! ``` -//! -//! To do this we can implement `AbsDiffEq`, `RelativeEq` and `UlpsEq` generically in terms of a -//! type parameter that also implements `ApproxEq`, `RelativeEq` and `UlpsEq` respectively. This -//! means that we can make comparisons for either `Complex` or `Complex`: -//! -//! ```rust -//! # use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -//! # #[derive(Debug, PartialEq)] -//! # struct Complex { x: T, i: T, } -//! # -//! impl AbsDiffEq for Complex where -//! T::Epsilon: Copy, -//! { -//! type Epsilon = T::Epsilon; -//! -//! fn default_epsilon() -> T::Epsilon { -//! T::default_epsilon() -//! } -//! -//! fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool { -//! T::abs_diff_eq(&self.x, &other.x, epsilon) && -//! T::abs_diff_eq(&self.i, &other.i, epsilon) -//! } -//! } -//! -//! impl RelativeEq for Complex where -//! T::Epsilon: Copy, -//! { -//! fn default_max_relative() -> T::Epsilon { -//! T::default_max_relative() -//! } -//! -//! fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool { -//! T::relative_eq(&self.x, &other.x, epsilon, max_relative) && -//! T::relative_eq(&self.i, &other.i, epsilon, max_relative) -//! } -//! } -//! -//! impl UlpsEq for Complex where -//! T::Epsilon: Copy, -//! { -//! fn default_max_ulps() -> u32 { -//! T::default_max_ulps() -//! } -//! -//! fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool { -//! T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) && -//! T::ulps_eq(&self.i, &other.i, epsilon, max_ulps) -//! } -//! } -//! ``` -//! -//! # References -//! -//! Floating point is hard! Thanks goes to these links for helping to make things a _little_ -//! easier to understand: -//! -//! - [Comparing Floating Point Numbers, 2012 Edition] -//! (https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) -//! - [The Floating Point Guide - Comparison](http://floating-point-gui.de/errors/comparison/) -//! - [What Every Computer Scientist Should Know About Floating-Point Arithmetic] -//! (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "num-complex")] -extern crate num_complex; -extern crate num_traits; - -#[cfg(not(feature = "std"))] -use core as std; - -mod abs_diff_eq; -mod relative_eq; -mod ulps_eq; - -mod macros; - -pub use abs_diff_eq::AbsDiffEq; -pub use relative_eq::RelativeEq; -pub use ulps_eq::UlpsEq; - -/// The requisite parameters for testing for approximate equality using a -/// absolute difference based comparison. -/// -/// This is not normally used directly, rather via the -/// `assert_abs_diff_{eq|ne}!` and `abs_diff_{eq|ne}!` macros. -/// -/// # Example -/// -/// ```rust -/// use std::f64; -/// use approx::AbsDiff; -/// -/// AbsDiff::default().eq(&1.0, &1.0); -/// AbsDiff::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); -/// ``` -pub struct AbsDiff -where - A: AbsDiffEq + ?Sized, - B: ?Sized, -{ - /// The tolerance to use when testing values that are close together. - pub epsilon: A::Epsilon, -} - -impl Default for AbsDiff -where - A: AbsDiffEq + ?Sized, - B: ?Sized, -{ - #[inline] - fn default() -> AbsDiff { - AbsDiff { - epsilon: A::default_epsilon(), - } - } -} - -impl AbsDiff -where - A: AbsDiffEq + ?Sized, - B: ?Sized, -{ - /// Replace the epsilon value with the one specified. - #[inline] - pub fn epsilon(self, epsilon: A::Epsilon) -> AbsDiff { - AbsDiff { epsilon, ..self } - } - - /// Peform the equality comparison - #[inline] - pub fn eq(self, lhs: &A, rhs: &B) -> bool { - A::abs_diff_eq(lhs, rhs, self.epsilon) - } - - /// Peform the inequality comparison - #[inline] - pub fn ne(self, lhs: &A, rhs: &B) -> bool { - A::abs_diff_ne(lhs, rhs, self.epsilon) - } -} - -/// The requisite parameters for testing for approximate equality using a -/// relative based comparison. -/// -/// This is not normally used directly, rather via the -/// `assert_relative_{eq|ne}!` and `relative_{eq|ne}!` macros. -/// -/// # Example -/// -/// ```rust -/// use std::f64; -/// use approx::Relative; -/// -/// Relative::default().eq(&1.0, &1.0); -/// Relative::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); -/// Relative::default().max_relative(1.0).eq(&1.0, &1.0); -/// Relative::default().epsilon(f64::EPSILON).max_relative(1.0).eq(&1.0, &1.0); -/// Relative::default().max_relative(1.0).epsilon(f64::EPSILON).eq(&1.0, &1.0); -/// ``` -pub struct Relative -where - A: RelativeEq + ?Sized, - B: ?Sized, -{ - /// The tolerance to use when testing values that are close together. - pub epsilon: A::Epsilon, - /// The relative tolerance for testing values that are far-apart. - pub max_relative: A::Epsilon, -} - -impl Default for Relative -where - A: RelativeEq + ?Sized, - B: ?Sized, -{ - #[inline] - fn default() -> Relative { - Relative { - epsilon: A::default_epsilon(), - max_relative: A::default_max_relative(), - } - } -} - -impl Relative -where - A: RelativeEq + ?Sized, - B: ?Sized, -{ - /// Replace the epsilon value with the one specified. - #[inline] - pub fn epsilon(self, epsilon: A::Epsilon) -> Relative { - Relative { epsilon, ..self } - } - - /// Replace the maximum relative value with the one specified. - #[inline] - pub fn max_relative(self, max_relative: A::Epsilon) -> Relative { - Relative { - max_relative, - ..self - } - } - - /// Peform the equality comparison - #[inline] - pub fn eq(self, lhs: &A, rhs: &B) -> bool { - A::relative_eq(lhs, rhs, self.epsilon, self.max_relative) - } - - /// Peform the inequality comparison - #[inline] - pub fn ne(self, lhs: &A, rhs: &B) -> bool { - A::relative_ne(lhs, rhs, self.epsilon, self.max_relative) - } -} - -/// The requisite parameters for testing for approximate equality using an ULPs -/// based comparison. -/// -/// This is not normally used directly, rather via the `assert_ulps_{eq|ne}!` -/// and `ulps_{eq|ne}!` macros. -/// -/// # Example -/// -/// ```rust -/// use std::f64; -/// use approx::Ulps; -/// -/// Ulps::default().eq(&1.0, &1.0); -/// Ulps::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); -/// Ulps::default().max_ulps(4).eq(&1.0, &1.0); -/// Ulps::default().epsilon(f64::EPSILON).max_ulps(4).eq(&1.0, &1.0); -/// Ulps::default().max_ulps(4).epsilon(f64::EPSILON).eq(&1.0, &1.0); -/// ``` -pub struct Ulps -where - A: UlpsEq + ?Sized, - B: ?Sized, -{ - /// The tolerance to use when testing values that are close together. - pub epsilon: A::Epsilon, - /// The ULPs to tolerate when testing values that are far-apart. - pub max_ulps: u32, -} - -impl Default for Ulps -where - A: UlpsEq + ?Sized, - B: ?Sized, -{ - #[inline] - fn default() -> Ulps { - Ulps { - epsilon: A::default_epsilon(), - max_ulps: A::default_max_ulps(), - } - } -} - -impl Ulps -where - A: UlpsEq + ?Sized, - B: ?Sized, -{ - /// Replace the epsilon value with the one specified. - #[inline] - pub fn epsilon(self, epsilon: A::Epsilon) -> Ulps { - Ulps { epsilon, ..self } - } - - /// Replace the max ulps value with the one specified. - #[inline] - pub fn max_ulps(self, max_ulps: u32) -> Ulps { - Ulps { max_ulps, ..self } - } - - /// Peform the equality comparison - #[inline] - pub fn eq(self, lhs: &A, rhs: &B) -> bool { - A::ulps_eq(lhs, rhs, self.epsilon, self.max_ulps) - } - - /// Peform the inequality comparison - #[inline] - pub fn ne(self, lhs: &A, rhs: &B) -> bool { - A::ulps_ne(lhs, rhs, self.epsilon, self.max_ulps) - } -} diff --git a/third_party/cargo/vendor/approx-0.3.2/src/macros.rs b/third_party/cargo/vendor/approx-0.3.2/src/macros.rs deleted file mode 100644 index 6462fb2..0000000 --- a/third_party/cargo/vendor/approx-0.3.2/src/macros.rs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 Brendan Zabarauskas -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/// Approximate equality of using the absolute difference. -#[macro_export] -macro_rules! abs_diff_eq { - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { - $crate::AbsDiff::default()$(.$opt($val))*.eq(&$lhs, &$rhs) - }; - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { - $crate::AbsDiff::default()$(.$opt($val))*.eq(&$lhs, &$rhs) - }; -} - -/// Approximate inequality of using the absolute difference. -#[macro_export] -macro_rules! abs_diff_ne { - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { - $crate::AbsDiff::default()$(.$opt($val))*.ne(&$lhs, &$rhs) - }; - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { - $crate::AbsDiff::default()$(.$opt($val))*.ne(&$lhs, &$rhs) - }; -} - -/// Approximate equality using both the absolute difference and relative based comparisons. -#[macro_export] -macro_rules! relative_eq { - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { - $crate::Relative::default()$(.$opt($val))*.eq(&$lhs, &$rhs) - }; - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { - $crate::Relative::default()$(.$opt($val))*.eq(&$lhs, &$rhs) - }; -} - -/// Approximate inequality using both the absolute difference and relative based comparisons. -#[macro_export] -macro_rules! relative_ne { - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { - $crate::Relative::default()$(.$opt($val))*.ne(&$lhs, &$rhs) - }; - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { - $crate::Relative::default()$(.$opt($val))*.ne(&$lhs, &$rhs) - }; -} - -/// Approximate equality using both the absolute difference and ULPs (Units in Last Place). -#[macro_export] -macro_rules! ulps_eq { - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { - $crate::Ulps::default()$(.$opt($val))*.eq(&$lhs, &$rhs) - }; - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { - $crate::Ulps::default()$(.$opt($val))*.eq(&$lhs, &$rhs) - }; -} - -/// Approximate inequality using both the absolute difference and ULPs (Units in Last Place). -#[macro_export] -macro_rules! ulps_ne { - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { - $crate::Ulps::default()$(.$opt($val))*.ne(&$lhs, &$rhs) - }; - ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { - $crate::Ulps::default()$(.$opt($val))*.ne(&$lhs, &$rhs) - }; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! __assert_approx { - ($eq:ident, $given:expr, $expected:expr) => {{ - let (given, expected) = (&($given), &($expected)); - - if !$eq!(*given, *expected) { - panic!( -"assert_{}!({}, {}) - - left = {:?} - right = {:?} - -", - stringify!($eq), - stringify!($given), - stringify!($expected), - given, expected, - ); - } - }}; - ($eq:ident, $given:expr, $expected:expr, $($opt:ident = $val:expr),+) => {{ - let (given, expected) = (&($given), &($expected)); - - if !$eq!(*given, *expected, $($opt = $val),+) { - panic!( -"assert_{}!({}, {}, {}) - - left = {:?} - right = {:?} - -", - stringify!($eq), - stringify!($given), - stringify!($expected), - stringify!($($opt = $val),+), - given, expected, - ); - } - }}; -} - -/// An assertion that delegates to `abs_diff_eq!`, and panics with a helpful error on failure. -#[macro_export(local_inner_macros)] -macro_rules! assert_abs_diff_eq { - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { - __assert_approx!(abs_diff_eq, $given, $expected $(, $opt = $val)*) - }; - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { - __assert_approx!(abs_diff_eq, $given, $expected $(, $opt = $val)*) - }; -} - -/// An assertion that delegates to `abs_diff_ne!`, and panics with a helpful error on failure. -#[macro_export(local_inner_macros)] -macro_rules! assert_abs_diff_ne { - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { - __assert_approx!(abs_diff_ne, $given, $expected $(, $opt = $val)*) - }; - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { - __assert_approx!(abs_diff_ne, $given, $expected $(, $opt = $val)*) - }; -} - -/// An assertion that delegates to `relative_eq!`, and panics with a helpful error on failure. -#[macro_export(local_inner_macros)] -macro_rules! assert_relative_eq { - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { - __assert_approx!(relative_eq, $given, $expected $(, $opt = $val)*) - }; - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { - __assert_approx!(relative_eq, $given, $expected $(, $opt = $val)*) - }; -} - -/// An assertion that delegates to `relative_ne!`, and panics with a helpful error on failure. -#[macro_export(local_inner_macros)] -macro_rules! assert_relative_ne { - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { - __assert_approx!(relative_ne, $given, $expected $(, $opt = $val)*) - }; - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { - __assert_approx!(relative_ne, $given, $expected $(, $opt = $val)*) - }; -} - -/// An assertion that delegates to `ulps_eq!`, and panics with a helpful error on failure. -#[macro_export(local_inner_macros)] -macro_rules! assert_ulps_eq { - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { - __assert_approx!(ulps_eq, $given, $expected $(, $opt = $val)*) - }; - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { - __assert_approx!(ulps_eq, $given, $expected $(, $opt = $val)*) - }; -} - -/// An assertion that delegates to `ulps_ne!`, and panics with a helpful error on failure. -#[macro_export(local_inner_macros)] -macro_rules! assert_ulps_ne { - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { - __assert_approx!(ulps_ne, $given, $expected $(, $opt = $val)*) - }; - ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { - __assert_approx!(ulps_ne, $given, $expected $(, $opt = $val)*) - }; -} diff --git a/third_party/cargo/vendor/approx-0.4.0/.cargo-checksum.json b/third_party/cargo/vendor/approx-0.4.0/.cargo-checksum.json new file mode 100644 index 0000000..f3a88d9 --- /dev/null +++ b/third_party/cargo/vendor/approx-0.4.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"9d06c01a157de4e9f7af0cc7b6ea1d8e3f88a44b213b14cc9e4e28ff50af07ae","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"5e965438ec90b7ede0a5c93c482a91536759c147e215f7471d8534f121feb244","src/abs_diff_eq.rs":"d1b333f1570a0bfe3b7958826aedf4fb8778aaf4b4a4b7abfe70458459402291","src/lib.rs":"d2da80db1e6af5c78310ccbf328513096d3e4ec183d73f82185fadc69fc75dcf","src/macros.rs":"772e24745b0311499bbe6615960957516cd5bda94c946678f57b96529c112450","src/relative_eq.rs":"9a791c63479ef713b37302e14575c945eab24f9424fb6a75bc027347da257c38","src/ulps_eq.rs":"0265077b572cffc4ccc93ac13cc121992cc9f25ce200912ca2070f41a167062b","tests/abs_diff_eq.rs":"9df9b48842dbc61b04b0328b64f2ce48b6e66e9538178babd58a9e52adeaddaf","tests/macro_import.rs":"006d813c99217d251a30b2f248548e7ad385754f88f6d9838d1dee866ea4b7f4","tests/macros.rs":"697241db4db66633cb53324bb127c64fd3b544236055bfe1721abb64a1dfab23","tests/relative_eq.rs":"c114edb6af07a2ac126e167682dd5d677d5591217f48bfdba150f866dfe4fdaf","tests/ulps_eq.rs":"ef6d57b98394fc87e724e26de7a3461426444563ec962661f660875b0702aeb6"},"package":"3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"} \ No newline at end of file diff --git a/third_party/cargo/vendor/approx-0.4.0/BUILD.bazel b/third_party/cargo/vendor/approx-0.4.0/BUILD.bazel new file mode 100644 index 0000000..cb0932a --- /dev/null +++ b/third_party/cargo/vendor/approx-0.4.0/BUILD.bazel @@ -0,0 +1,66 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Apache-2.0 from expression "Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "approx", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.4.0", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/num-traits-0.2.14:num_traits", + ], +) + +# Unsupported target "abs_diff_eq" with type "test" omitted + +# Unsupported target "macro_import" with type "test" omitted + +# Unsupported target "macros" with type "test" omitted + +# Unsupported target "relative_eq" with type "test" omitted + +# Unsupported target "ulps_eq" with type "test" omitted diff --git a/third_party/cargo/vendor/approx-0.4.0/Cargo.toml b/third_party/cargo/vendor/approx-0.4.0/Cargo.toml new file mode 100644 index 0000000..2156532 --- /dev/null +++ b/third_party/cargo/vendor/approx-0.4.0/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "approx" +version = "0.4.0" +authors = ["Brendan Zabarauskas "] +description = "Approximate floating point equality comparisons and assertions." +homepage = "https://github.com/brendanzab/approx" +documentation = "https://docs.rs/approx" +readme = "README.md" +keywords = ["approximate", "assert", "comparison", "equality", "float"] +license = "Apache-2.0" +repository = "https://github.com/brendanzab/approx" +[package.metadata.docs.rs] +features = ["std", "num-complex"] + +[lib] +name = "approx" +[dependencies.num-complex] +version = "0.3.0" +optional = true + +[dependencies.num-traits] +version = "0.2.0" +default_features = false + +[features] +default = ["std"] +std = [] diff --git a/third_party/cargo/vendor/approx-0.3.2/LICENSE b/third_party/cargo/vendor/approx-0.4.0/LICENSE similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/LICENSE rename to third_party/cargo/vendor/approx-0.4.0/LICENSE diff --git a/third_party/cargo/vendor/approx-0.3.2/README.md b/third_party/cargo/vendor/approx-0.4.0/README.md similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/README.md rename to third_party/cargo/vendor/approx-0.4.0/README.md diff --git a/third_party/cargo/vendor/approx-0.3.2/src/abs_diff_eq.rs b/third_party/cargo/vendor/approx-0.4.0/src/abs_diff_eq.rs similarity index 97% rename from third_party/cargo/vendor/approx-0.3.2/src/abs_diff_eq.rs rename to third_party/cargo/vendor/approx-0.4.0/src/abs_diff_eq.rs index 67f59c7..ebcd6cf 100644 --- a/third_party/cargo/vendor/approx-0.3.2/src/abs_diff_eq.rs +++ b/third_party/cargo/vendor/approx-0.4.0/src/abs_diff_eq.rs @@ -14,15 +14,15 @@ where /// The default tolerance to use when testing values that are close together. /// - /// This is used when no `epsilon` value is supplied to the `abs_diff_eq!`, `relative_eq!`, or - /// `ulps_eq!` macros. + /// This is used when no `epsilon` value is supplied to the [`abs_diff_eq!`], [`relative_eq!`], + /// or [`ulps_eq!`] macros. fn default_epsilon() -> Self::Epsilon; /// A test for equality that uses the absolute difference to compute the approximate /// equality of two numbers. fn abs_diff_eq(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool; - /// The inverse of `ApproxEq::abs_diff_eq`. + /// The inverse of [`AbsDiffEq::abs_diff_eq`]. fn abs_diff_ne(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool { !Self::abs_diff_eq(self, other, epsilon) } diff --git a/third_party/cargo/vendor/approx-0.4.0/src/lib.rs b/third_party/cargo/vendor/approx-0.4.0/src/lib.rs new file mode 100644 index 0000000..479e788 --- /dev/null +++ b/third_party/cargo/vendor/approx-0.4.0/src/lib.rs @@ -0,0 +1,390 @@ +// Copyright 2015 Brendan Zabarauskas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A crate that provides facilities for testing the approximate equality of floating-point +//! based types, using either relative difference, or units in the last place (ULPs) +//! comparisons. +//! +//! You can also use the `*_{eq, ne}!` and `assert_*_{eq, ne}!` macros to test for equality using a +//! more positional style: +//! +//! ```rust +//! #[macro_use] +//! extern crate approx; +//! +//! use std::f64; +//! +//! # fn main() { +//! abs_diff_eq!(1.0, 1.0); +//! abs_diff_eq!(1.0, 1.0, epsilon = f64::EPSILON); +//! +//! relative_eq!(1.0, 1.0); +//! relative_eq!(1.0, 1.0, epsilon = f64::EPSILON); +//! relative_eq!(1.0, 1.0, max_relative = 1.0); +//! relative_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_relative = 1.0); +//! relative_eq!(1.0, 1.0, max_relative = 1.0, epsilon = f64::EPSILON); +//! +//! ulps_eq!(1.0, 1.0); +//! ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON); +//! ulps_eq!(1.0, 1.0, max_ulps = 4); +//! ulps_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_ulps = 4); +//! ulps_eq!(1.0, 1.0, max_ulps = 4, epsilon = f64::EPSILON); +//! # } +//! ``` +//! +//! # Implementing approximate equality for custom types +//! +//! The `*Eq` traits allow approximate equalities to be implemented on types, based on the +//! fundamental floating point implementations. +//! +//! For example, we might want to be able to do approximate assertions on a complex number type: +//! +//! ```rust +//! #[macro_use] +//! extern crate approx; +//! # use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +//! +//! #[derive(Debug, PartialEq)] +//! struct Complex { +//! x: T, +//! i: T, +//! } +//! # impl AbsDiffEq for Complex where T::Epsilon: Copy { +//! # type Epsilon = T::Epsilon; +//! # fn default_epsilon() -> T::Epsilon { T::default_epsilon() } +//! # fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool { +//! # T::abs_diff_eq(&self.x, &other.x, epsilon) && +//! # T::abs_diff_eq(&self.i, &other.i, epsilon) +//! # } +//! # } +//! # impl RelativeEq for Complex where T::Epsilon: Copy { +//! # fn default_max_relative() -> T::Epsilon { T::default_max_relative() } +//! # fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) +//! # -> bool { +//! # T::relative_eq(&self.x, &other.x, epsilon, max_relative) && +//! # T::relative_eq(&self.i, &other.i, epsilon, max_relative) +//! # } +//! # } +//! # impl UlpsEq for Complex where T::Epsilon: Copy { +//! # fn default_max_ulps() -> u32 { T::default_max_ulps() } +//! # fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool { +//! # T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) && +//! # T::ulps_eq(&self.i, &other.i, epsilon, max_ulps) +//! # } +//! # } +//! +//! # fn main() { +//! let x = Complex { x: 1.2, i: 2.3 }; +//! +//! assert_relative_eq!(x, x); +//! assert_ulps_eq!(x, x, max_ulps = 4); +//! # } +//! ``` +//! +//! To do this we can implement [`AbsDiffEq`], [`RelativeEq`] and [`UlpsEq`] generically in terms +//! of a type parameter that also implements `AbsDiffEq`, `RelativeEq` and `UlpsEq` respectively. +//! This means that we can make comparisons for either `Complex` or `Complex`: +//! +//! ```rust +//! # use approx::{AbsDiffEq, RelativeEq, UlpsEq}; +//! # #[derive(Debug, PartialEq)] +//! # struct Complex { x: T, i: T, } +//! # +//! impl AbsDiffEq for Complex where +//! T::Epsilon: Copy, +//! { +//! type Epsilon = T::Epsilon; +//! +//! fn default_epsilon() -> T::Epsilon { +//! T::default_epsilon() +//! } +//! +//! fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool { +//! T::abs_diff_eq(&self.x, &other.x, epsilon) && +//! T::abs_diff_eq(&self.i, &other.i, epsilon) +//! } +//! } +//! +//! impl RelativeEq for Complex where +//! T::Epsilon: Copy, +//! { +//! fn default_max_relative() -> T::Epsilon { +//! T::default_max_relative() +//! } +//! +//! fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool { +//! T::relative_eq(&self.x, &other.x, epsilon, max_relative) && +//! T::relative_eq(&self.i, &other.i, epsilon, max_relative) +//! } +//! } +//! +//! impl UlpsEq for Complex where +//! T::Epsilon: Copy, +//! { +//! fn default_max_ulps() -> u32 { +//! T::default_max_ulps() +//! } +//! +//! fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool { +//! T::ulps_eq(&self.x, &other.x, epsilon, max_ulps) && +//! T::ulps_eq(&self.i, &other.i, epsilon, max_ulps) +//! } +//! } +//! ``` +//! +//! # References +//! +//! Floating point is hard! Thanks goes to these links for helping to make things a _little_ +//! easier to understand: +//! +//! - [Comparing Floating Point Numbers, 2012 Edition]( +//! https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/) +//! - [The Floating Point Guide - Comparison](http://floating-point-gui.de/errors/comparison/) +//! - [What Every Computer Scientist Should Know About Floating-Point Arithmetic]( +//! https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "num-complex")] +extern crate num_complex; +extern crate num_traits; + +#[cfg(not(feature = "std"))] +use core as std; + +mod abs_diff_eq; +mod relative_eq; +mod ulps_eq; + +mod macros; + +pub use abs_diff_eq::AbsDiffEq; +pub use relative_eq::RelativeEq; +pub use ulps_eq::UlpsEq; + +/// The requisite parameters for testing for approximate equality using a +/// absolute difference based comparison. +/// +/// This is not normally used directly, rather via the +/// `assert_abs_diff_{eq|ne}!` and `abs_diff_{eq|ne}!` macros. +/// +/// # Example +/// +/// ```rust +/// use std::f64; +/// use approx::AbsDiff; +/// +/// AbsDiff::default().eq(&1.0, &1.0); +/// AbsDiff::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); +/// ``` +pub struct AbsDiff +where + A: AbsDiffEq + ?Sized, + B: ?Sized, +{ + /// The tolerance to use when testing values that are close together. + pub epsilon: A::Epsilon, +} + +impl Default for AbsDiff +where + A: AbsDiffEq + ?Sized, + B: ?Sized, +{ + #[inline] + fn default() -> AbsDiff { + AbsDiff { + epsilon: A::default_epsilon(), + } + } +} + +impl AbsDiff +where + A: AbsDiffEq + ?Sized, + B: ?Sized, +{ + /// Replace the epsilon value with the one specified. + #[inline] + pub fn epsilon(self, epsilon: A::Epsilon) -> AbsDiff { + AbsDiff { epsilon, ..self } + } + + /// Peform the equality comparison + #[inline] + #[must_use] + pub fn eq(self, lhs: &A, rhs: &B) -> bool { + A::abs_diff_eq(lhs, rhs, self.epsilon) + } + + /// Peform the inequality comparison + #[inline] + #[must_use] + pub fn ne(self, lhs: &A, rhs: &B) -> bool { + A::abs_diff_ne(lhs, rhs, self.epsilon) + } +} + +/// The requisite parameters for testing for approximate equality using a +/// relative based comparison. +/// +/// This is not normally used directly, rather via the +/// `assert_relative_{eq|ne}!` and `relative_{eq|ne}!` macros. +/// +/// # Example +/// +/// ```rust +/// use std::f64; +/// use approx::Relative; +/// +/// Relative::default().eq(&1.0, &1.0); +/// Relative::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); +/// Relative::default().max_relative(1.0).eq(&1.0, &1.0); +/// Relative::default().epsilon(f64::EPSILON).max_relative(1.0).eq(&1.0, &1.0); +/// Relative::default().max_relative(1.0).epsilon(f64::EPSILON).eq(&1.0, &1.0); +/// ``` +pub struct Relative +where + A: RelativeEq + ?Sized, + B: ?Sized, +{ + /// The tolerance to use when testing values that are close together. + pub epsilon: A::Epsilon, + /// The relative tolerance for testing values that are far-apart. + pub max_relative: A::Epsilon, +} + +impl Default for Relative +where + A: RelativeEq + ?Sized, + B: ?Sized, +{ + #[inline] + fn default() -> Relative { + Relative { + epsilon: A::default_epsilon(), + max_relative: A::default_max_relative(), + } + } +} + +impl Relative +where + A: RelativeEq + ?Sized, + B: ?Sized, +{ + /// Replace the epsilon value with the one specified. + #[inline] + pub fn epsilon(self, epsilon: A::Epsilon) -> Relative { + Relative { epsilon, ..self } + } + + /// Replace the maximum relative value with the one specified. + #[inline] + pub fn max_relative(self, max_relative: A::Epsilon) -> Relative { + Relative { + max_relative, + ..self + } + } + + /// Peform the equality comparison + #[inline] + #[must_use] + pub fn eq(self, lhs: &A, rhs: &B) -> bool { + A::relative_eq(lhs, rhs, self.epsilon, self.max_relative) + } + + /// Peform the inequality comparison + #[inline] + #[must_use] + pub fn ne(self, lhs: &A, rhs: &B) -> bool { + A::relative_ne(lhs, rhs, self.epsilon, self.max_relative) + } +} + +/// The requisite parameters for testing for approximate equality using an ULPs +/// based comparison. +/// +/// This is not normally used directly, rather via the `assert_ulps_{eq|ne}!` +/// and `ulps_{eq|ne}!` macros. +/// +/// # Example +/// +/// ```rust +/// use std::f64; +/// use approx::Ulps; +/// +/// Ulps::default().eq(&1.0, &1.0); +/// Ulps::default().epsilon(f64::EPSILON).eq(&1.0, &1.0); +/// Ulps::default().max_ulps(4).eq(&1.0, &1.0); +/// Ulps::default().epsilon(f64::EPSILON).max_ulps(4).eq(&1.0, &1.0); +/// Ulps::default().max_ulps(4).epsilon(f64::EPSILON).eq(&1.0, &1.0); +/// ``` +pub struct Ulps +where + A: UlpsEq + ?Sized, + B: ?Sized, +{ + /// The tolerance to use when testing values that are close together. + pub epsilon: A::Epsilon, + /// The ULPs to tolerate when testing values that are far-apart. + pub max_ulps: u32, +} + +impl Default for Ulps +where + A: UlpsEq + ?Sized, + B: ?Sized, +{ + #[inline] + fn default() -> Ulps { + Ulps { + epsilon: A::default_epsilon(), + max_ulps: A::default_max_ulps(), + } + } +} + +impl Ulps +where + A: UlpsEq + ?Sized, + B: ?Sized, +{ + /// Replace the epsilon value with the one specified. + #[inline] + pub fn epsilon(self, epsilon: A::Epsilon) -> Ulps { + Ulps { epsilon, ..self } + } + + /// Replace the max ulps value with the one specified. + #[inline] + pub fn max_ulps(self, max_ulps: u32) -> Ulps { + Ulps { max_ulps, ..self } + } + + /// Peform the equality comparison + #[inline] + #[must_use] + pub fn eq(self, lhs: &A, rhs: &B) -> bool { + A::ulps_eq(lhs, rhs, self.epsilon, self.max_ulps) + } + + /// Peform the inequality comparison + #[inline] + #[must_use] + pub fn ne(self, lhs: &A, rhs: &B) -> bool { + A::ulps_ne(lhs, rhs, self.epsilon, self.max_ulps) + } +} diff --git a/third_party/cargo/vendor/approx-0.4.0/src/macros.rs b/third_party/cargo/vendor/approx-0.4.0/src/macros.rs new file mode 100644 index 0000000..d0fc81e --- /dev/null +++ b/third_party/cargo/vendor/approx-0.4.0/src/macros.rs @@ -0,0 +1,187 @@ +// Copyright 2015 Brendan Zabarauskas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Approximate equality of using the absolute difference. +#[macro_export] +macro_rules! abs_diff_eq { + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { + $crate::AbsDiff::default()$(.$opt($val))*.eq(&$lhs, &$rhs) + }; + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { + $crate::AbsDiff::default()$(.$opt($val))*.eq(&$lhs, &$rhs) + }; +} + +/// Approximate inequality of using the absolute difference. +#[macro_export] +macro_rules! abs_diff_ne { + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { + $crate::AbsDiff::default()$(.$opt($val))*.ne(&$lhs, &$rhs) + }; + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { + $crate::AbsDiff::default()$(.$opt($val))*.ne(&$lhs, &$rhs) + }; +} + +/// Approximate equality using both the absolute difference and relative based comparisons. +#[macro_export] +macro_rules! relative_eq { + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { + $crate::Relative::default()$(.$opt($val))*.eq(&$lhs, &$rhs) + }; + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { + $crate::Relative::default()$(.$opt($val))*.eq(&$lhs, &$rhs) + }; +} + +/// Approximate inequality using both the absolute difference and relative based comparisons. +#[macro_export] +macro_rules! relative_ne { + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { + $crate::Relative::default()$(.$opt($val))*.ne(&$lhs, &$rhs) + }; + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { + $crate::Relative::default()$(.$opt($val))*.ne(&$lhs, &$rhs) + }; +} + +/// Approximate equality using both the absolute difference and ULPs (Units in Last Place). +#[macro_export] +macro_rules! ulps_eq { + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { + $crate::Ulps::default()$(.$opt($val))*.eq(&$lhs, &$rhs) + }; + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { + $crate::Ulps::default()$(.$opt($val))*.eq(&$lhs, &$rhs) + }; +} + +/// Approximate inequality using both the absolute difference and ULPs (Units in Last Place). +#[macro_export] +macro_rules! ulps_ne { + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*) => { + $crate::Ulps::default()$(.$opt($val))*.ne(&$lhs, &$rhs) + }; + ($lhs:expr, $rhs:expr $(, $opt:ident = $val:expr)*,) => { + $crate::Ulps::default()$(.$opt($val))*.ne(&$lhs, &$rhs) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __assert_approx { + ($eq:ident, $given:expr, $expected:expr) => {{ + let (given, expected) = (&($given), &($expected)); + + if !$eq!(*given, *expected) { + panic!( +"assert_{}!({}, {}) + + left = {:?} + right = {:?} + +", + stringify!($eq), + stringify!($given), + stringify!($expected), + given, expected, + ); + } + }}; + ($eq:ident, $given:expr, $expected:expr, $($opt:ident = $val:expr),+) => {{ + let (given, expected) = (&($given), &($expected)); + + if !$eq!(*given, *expected, $($opt = $val),+) { + panic!( +"assert_{}!({}, {}, {}) + + left = {:?} + right = {:?} + +", + stringify!($eq), + stringify!($given), + stringify!($expected), + stringify!($($opt = $val),+), + given, expected, + ); + } + }}; +} + +/// An assertion that delegates to [`abs_diff_eq!`], and panics with a helpful error on failure. +#[macro_export(local_inner_macros)] +macro_rules! assert_abs_diff_eq { + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { + __assert_approx!(abs_diff_eq, $given, $expected $(, $opt = $val)*) + }; + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { + __assert_approx!(abs_diff_eq, $given, $expected $(, $opt = $val)*) + }; +} + +/// An assertion that delegates to [`abs_diff_ne!`], and panics with a helpful error on failure. +#[macro_export(local_inner_macros)] +macro_rules! assert_abs_diff_ne { + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { + __assert_approx!(abs_diff_ne, $given, $expected $(, $opt = $val)*) + }; + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { + __assert_approx!(abs_diff_ne, $given, $expected $(, $opt = $val)*) + }; +} + +/// An assertion that delegates to [`relative_eq!`], and panics with a helpful error on failure. +#[macro_export(local_inner_macros)] +macro_rules! assert_relative_eq { + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { + __assert_approx!(relative_eq, $given, $expected $(, $opt = $val)*) + }; + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { + __assert_approx!(relative_eq, $given, $expected $(, $opt = $val)*) + }; +} + +/// An assertion that delegates to [`relative_ne!`], and panics with a helpful error on failure. +#[macro_export(local_inner_macros)] +macro_rules! assert_relative_ne { + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { + __assert_approx!(relative_ne, $given, $expected $(, $opt = $val)*) + }; + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { + __assert_approx!(relative_ne, $given, $expected $(, $opt = $val)*) + }; +} + +/// An assertion that delegates to [`ulps_eq!`], and panics with a helpful error on failure. +#[macro_export(local_inner_macros)] +macro_rules! assert_ulps_eq { + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { + __assert_approx!(ulps_eq, $given, $expected $(, $opt = $val)*) + }; + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { + __assert_approx!(ulps_eq, $given, $expected $(, $opt = $val)*) + }; +} + +/// An assertion that delegates to [`ulps_ne!`], and panics with a helpful error on failure. +#[macro_export(local_inner_macros)] +macro_rules! assert_ulps_ne { + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*) => { + __assert_approx!(ulps_ne, $given, $expected $(, $opt = $val)*) + }; + ($given:expr, $expected:expr $(, $opt:ident = $val:expr)*,) => { + __assert_approx!(ulps_ne, $given, $expected $(, $opt = $val)*) + }; +} diff --git a/third_party/cargo/vendor/approx-0.3.2/src/relative_eq.rs b/third_party/cargo/vendor/approx-0.4.0/src/relative_eq.rs similarity index 98% rename from third_party/cargo/vendor/approx-0.3.2/src/relative_eq.rs rename to third_party/cargo/vendor/approx-0.4.0/src/relative_eq.rs index 5498825..2cf7cb7 100644 --- a/third_party/cargo/vendor/approx-0.3.2/src/relative_eq.rs +++ b/third_party/cargo/vendor/approx-0.4.0/src/relative_eq.rs @@ -14,7 +14,7 @@ where { /// The default relative tolerance for testing values that are far-apart. /// - /// This is used when no `max_relative` value is supplied to the `relative_eq` macro. + /// This is used when no `max_relative` value is supplied to the [`relative_eq`] macro. fn default_max_relative() -> Self::Epsilon; /// A test for equality that uses a relative comparison if the values are far apart. @@ -25,7 +25,7 @@ where max_relative: Self::Epsilon, ) -> bool; - /// The inverse of `ApproxEq::relative_eq`. + /// The inverse of [`RelativeEq::relative_eq`]. fn relative_ne( &self, other: &Rhs, diff --git a/third_party/cargo/vendor/approx-0.3.2/src/ulps_eq.rs b/third_party/cargo/vendor/approx-0.4.0/src/ulps_eq.rs similarity index 98% rename from third_party/cargo/vendor/approx-0.3.2/src/ulps_eq.rs rename to third_party/cargo/vendor/approx-0.4.0/src/ulps_eq.rs index b177aaa..b17f62c 100644 --- a/third_party/cargo/vendor/approx-0.3.2/src/ulps_eq.rs +++ b/third_party/cargo/vendor/approx-0.4.0/src/ulps_eq.rs @@ -14,13 +14,13 @@ where { /// The default ULPs to tolerate when testing values that are far-apart. /// - /// This is used when no `max_ulps` value is supplied to the `ulps_eq` macro. + /// This is used when no `max_ulps` value is supplied to the [`ulps_eq`] macro. fn default_max_ulps() -> u32; /// A test for equality that uses units in the last place (ULP) if the values are far apart. fn ulps_eq(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool; - /// The inverse of `ApproxEq::ulps_eq`. + /// The inverse of [`UlpsEq::ulps_eq`]. fn ulps_ne(&self, other: &Rhs, epsilon: Self::Epsilon, max_ulps: u32) -> bool { !Self::ulps_eq(self, other, epsilon, max_ulps) } diff --git a/third_party/cargo/vendor/approx-0.3.2/tests/abs_diff_eq.rs b/third_party/cargo/vendor/approx-0.4.0/tests/abs_diff_eq.rs similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/tests/abs_diff_eq.rs rename to third_party/cargo/vendor/approx-0.4.0/tests/abs_diff_eq.rs diff --git a/third_party/cargo/vendor/approx-0.3.2/tests/macro_import.rs b/third_party/cargo/vendor/approx-0.4.0/tests/macro_import.rs similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/tests/macro_import.rs rename to third_party/cargo/vendor/approx-0.4.0/tests/macro_import.rs diff --git a/third_party/cargo/vendor/approx-0.3.2/tests/macros.rs b/third_party/cargo/vendor/approx-0.4.0/tests/macros.rs similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/tests/macros.rs rename to third_party/cargo/vendor/approx-0.4.0/tests/macros.rs diff --git a/third_party/cargo/vendor/approx-0.3.2/tests/relative_eq.rs b/third_party/cargo/vendor/approx-0.4.0/tests/relative_eq.rs similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/tests/relative_eq.rs rename to third_party/cargo/vendor/approx-0.4.0/tests/relative_eq.rs diff --git a/third_party/cargo/vendor/approx-0.3.2/tests/ulps_eq.rs b/third_party/cargo/vendor/approx-0.4.0/tests/ulps_eq.rs similarity index 100% rename from third_party/cargo/vendor/approx-0.3.2/tests/ulps_eq.rs rename to third_party/cargo/vendor/approx-0.4.0/tests/ulps_eq.rs diff --git a/third_party/cargo/vendor/atty-0.2.14/BUILD.bazel b/third_party/cargo/vendor/atty-0.2.14/BUILD.bazel index 427de89..cfb97af 100644 --- a/third_party/cargo/vendor/atty-0.2.14/BUILD.bazel +++ b/third_party/cargo/vendor/atty-0.2.14/BUILD.bazel @@ -58,7 +58,7 @@ rust_library( ( "@io_bazel_rules_rust//rust/platform:x86_64-unknown-linux-gnu", ): [ - "//third_party/cargo/vendor/libc-0.2.71:libc", + "//third_party/cargo/vendor/libc-0.2.82:libc", ], "//conditions:default": [], }), diff --git a/third_party/cargo/vendor/autocfg-0.1.7/.cargo-checksum.json b/third_party/cargo/vendor/autocfg-0.1.7/.cargo-checksum.json deleted file mode 100644 index 87bafe6..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"745ff40f42e9a1275945a9db2763deeac749909e81d8d91859948fab49f5c268","Cargo.toml":"4072e465bb2d1110644171c28d1a48a8cf5e9bb85c75d39409bb719348a131f6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"0ff4942223d94c9686f846bb0b1de12221f06e7f39c1818ecbaaec402e89e770","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"374704e933dc6263a334652144e4436a7e409f88069c2f4f8e8c4ef14f7aa76b","src/tests.rs":"0b1353344e832553d328c47f1639ced877b5dff70fd2024d84130bd1c33eee07","src/version.rs":"175727d5f02f2fe2271ddc9b041db2a5b9c6fe0f95afd17c73a4d982612764a3","tests/rustflags.rs":"a3788396e0b81a33406d06fef3bc31c5a328f323de6766570a345ebad885cbf9"},"package":"1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"} \ No newline at end of file diff --git a/third_party/cargo/vendor/autocfg-0.1.7/BUILD.bazel b/third_party/cargo/vendor/autocfg-0.1.7/BUILD.bazel deleted file mode 100644 index 5038f69..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/BUILD.bazel +++ /dev/null @@ -1,63 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # Apache-2.0 from expression "Apache-2.0 OR MIT" -]) - -# Generated Targets - -# Unsupported target "integers" with type "example" omitted - -# Unsupported target "paths" with type "example" omitted - -# Unsupported target "traits" with type "example" omitted - -# Unsupported target "versions" with type "example" omitted - -rust_library( - name = "autocfg", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.1.7", - # buildifier: leave-alone - deps = [ - ], -) - -# Unsupported target "rustflags" with type "test" omitted diff --git a/third_party/cargo/vendor/autocfg-0.1.7/Cargo.lock b/third_party/cargo/vendor/autocfg-0.1.7/Cargo.lock deleted file mode 100644 index 670c6c2..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "0.1.7" - diff --git a/third_party/cargo/vendor/autocfg-0.1.7/Cargo.toml b/third_party/cargo/vendor/autocfg-0.1.7/Cargo.toml deleted file mode 100644 index c077b3e..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "autocfg" -version = "0.1.7" -authors = ["Josh Stone "] -description = "Automatic cfg for Rust compiler features" -readme = "README.md" -keywords = ["rustc", "build", "autoconf"] -categories = ["development-tools::build-utils"] -license = "Apache-2.0/MIT" -repository = "https://github.com/cuviper/autocfg" - -[dependencies] diff --git a/third_party/cargo/vendor/autocfg-0.1.7/README.md b/third_party/cargo/vendor/autocfg-0.1.7/README.md deleted file mode 100644 index 680f11e..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/README.md +++ /dev/null @@ -1,84 +0,0 @@ -autocfg -======= - -[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg) -[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg) -![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg) -[![Travis Status](https://travis-ci.org/cuviper/autocfg.svg?branch=master)](https://travis-ci.org/cuviper/autocfg) - -A Rust library for build scripts to automatically configure code based on -compiler support. Code snippets are dynamically tested to see if the `rustc` -will accept them, rather than hard-coding specific version support. - - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[build-dependencies] -autocfg = "0.1" -``` - -Then use it in your `build.rs` script to detect compiler features. For -example, to test for 128-bit integer support, it might look like: - -```rust -extern crate autocfg; - -fn main() { - let ac = autocfg::new(); - ac.emit_has_type("i128"); - - // (optional) We don't need to rerun for anything external. - autocfg::rerun_path(file!()); -} -``` - -If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line -for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the -rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that -should only be used when the compiler supports it. - - -## Release Notes - -- 0.1.7 (2019-10-20) - - Apply `RUSTFLAGS` when probing `$TARGET != $HOST`, mainly for sysroot, by @roblabla. - -- 0.1.6 (2019-08-19) - - Add `probe`/`emit_sysroot_crate`, by @leo60228. - -- 0.1.5 (2019-07-16) - - Mask some warnings from newer rustc. - -- 0.1.4 (2019-05-22) - - Relax `std`/`no_std` probing to a warning instead of an error. - - Improve `rustc` bootstrap compatibility. - -- 0.1.3 (2019-05-21) - - Auto-detects if `#![no_std]` is needed for the `$TARGET`. - -- 0.1.2 (2019-01-16) - - Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV`. - - Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH`. - - -## Minimum Rust version policy - -This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is -its entire reason for existence, so this crate will be extremely conservative -about raising this requirement. If this is ever deemed necessary, it will be -treated as a major breaking change for semver purposes. - - -## License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. diff --git a/third_party/cargo/vendor/autocfg-0.1.7/src/lib.rs b/third_party/cargo/vendor/autocfg-0.1.7/src/lib.rs deleted file mode 100644 index d563700..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/src/lib.rs +++ /dev/null @@ -1,366 +0,0 @@ -//! A Rust library for build scripts to automatically configure code based on -//! compiler support. Code snippets are dynamically tested to see if the `rustc` -//! will accept them, rather than hard-coding specific version support. -//! -//! -//! ## Usage -//! -//! Add this to your `Cargo.toml`: -//! -//! ```toml -//! [build-dependencies] -//! autocfg = "0.1" -//! ``` -//! -//! Then use it in your `build.rs` script to detect compiler features. For -//! example, to test for 128-bit integer support, it might look like: -//! -//! ```rust -//! extern crate autocfg; -//! -//! fn main() { -//! # // Normally, cargo will set `OUT_DIR` for build scripts. -//! # std::env::set_var("OUT_DIR", "target"); -//! let ac = autocfg::new(); -//! ac.emit_has_type("i128"); -//! -//! // (optional) We don't need to rerun for anything external. -//! autocfg::rerun_path(file!()); -//! } -//! ``` -//! -//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line -//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the -//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that -//! should only be used when the compiler supports it. - -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -// allow future warnings that can't be fixed while keeping 1.0 compatibility -#![allow(unknown_lints)] -#![allow(bare_trait_objects)] -#![allow(ellipsis_inclusive_range_patterns)] - -/// Local macro to avoid `std::try!`, deprecated in Rust 1.39. -macro_rules! try { - ($result:expr) => { - match $result { - Ok(value) => value, - Err(error) => return Err(error), - } - }; -} - -use std::env; -use std::ffi::OsString; -use std::fs; -use std::io::{stderr, Write}; -use std::path::PathBuf; -use std::process::{Command, Stdio}; -#[allow(deprecated)] -use std::sync::atomic::ATOMIC_USIZE_INIT; -use std::sync::atomic::{AtomicUsize, Ordering}; - -mod error; -pub use error::Error; - -mod version; -use version::Version; - -#[cfg(test)] -mod tests; - -/// Helper to detect compiler features for `cfg` output in build scripts. -#[derive(Clone, Debug)] -pub struct AutoCfg { - out_dir: PathBuf, - rustc: PathBuf, - rustc_version: Version, - target: Option, - no_std: bool, - rustflags: Option>, -} - -/// Writes a config flag for rustc on standard out. -/// -/// This looks like: `cargo:rustc-cfg=CFG` -/// -/// Cargo will use this in arguments to rustc, like `--cfg CFG`. -pub fn emit(cfg: &str) { - println!("cargo:rustc-cfg={}", cfg); -} - -/// Writes a line telling Cargo to rerun the build script if `path` changes. -/// -/// This looks like: `cargo:rerun-if-changed=PATH` -/// -/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier -/// versions of cargo will simply ignore the directive. -pub fn rerun_path(path: &str) { - println!("cargo:rerun-if-changed={}", path); -} - -/// Writes a line telling Cargo to rerun the build script if the environment -/// variable `var` changes. -/// -/// This looks like: `cargo:rerun-if-env-changed=VAR` -/// -/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier -/// versions of cargo will simply ignore the directive. -pub fn rerun_env(var: &str) { - println!("cargo:rerun-if-env-changed={}", var); -} - -/// Create a new `AutoCfg` instance. -/// -/// # Panics -/// -/// Panics if `AutoCfg::new()` returns an error. -pub fn new() -> AutoCfg { - AutoCfg::new().unwrap() -} - -impl AutoCfg { - /// Create a new `AutoCfg` instance. - /// - /// # Common errors - /// - /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. - /// - The version output from `rustc` can't be parsed. - /// - `OUT_DIR` is not set in the environment, or is not a writable directory. - /// - pub fn new() -> Result { - match env::var_os("OUT_DIR") { - Some(d) => Self::with_dir(d), - None => Err(error::from_str("no OUT_DIR specified!")), - } - } - - /// Create a new `AutoCfg` instance with the specified output directory. - /// - /// # Common errors - /// - /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. - /// - The version output from `rustc` can't be parsed. - /// - `dir` is not a writable directory. - /// - pub fn with_dir>(dir: T) -> Result { - let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); - let rustc: PathBuf = rustc.into(); - let rustc_version = try!(Version::from_rustc(&rustc)); - - // Sanity check the output directory - let dir = dir.into(); - let meta = try!(fs::metadata(&dir).map_err(error::from_io)); - if !meta.is_dir() || meta.permissions().readonly() { - return Err(error::from_str("output path is not a writable directory")); - } - - // Cargo only applies RUSTFLAGS for building TARGET artifact in - // cross-compilation environment. Sadly, we don't have a way to detect - // when we're building HOST artifact in a cross-compilation environment, - // so for now we only apply RUSTFLAGS when cross-compiling an artifact. - // - // See https://github.com/cuviper/autocfg/pull/10#issuecomment-527575030. - let rustflags = if env::var_os("TARGET") != env::var_os("HOST") { - env::var("RUSTFLAGS").ok().map(|rustflags| { - // This is meant to match how cargo handles the RUSTFLAG environment - // variable. - // See https://github.com/rust-lang/cargo/blob/69aea5b6f69add7c51cca939a79644080c0b0ba0/src/cargo/core/compiler/build_context/target_info.rs#L434-L441 - rustflags - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(str::to_string) - .collect::>() - }) - } else { - None - }; - - let mut ac = AutoCfg { - out_dir: dir, - rustc: rustc, - rustc_version: rustc_version, - target: env::var_os("TARGET"), - no_std: false, - rustflags: rustflags, - }; - - // Sanity check with and without `std`. - if !ac.probe("").unwrap_or(false) { - ac.no_std = true; - if !ac.probe("").unwrap_or(false) { - // Neither worked, so assume nothing... - ac.no_std = false; - let warning = b"warning: autocfg could not probe for `std`\n"; - stderr().write_all(warning).ok(); - } - } - Ok(ac) - } - - /// Test whether the current `rustc` reports a version greater than - /// or equal to "`major`.`minor`". - pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool { - self.rustc_version >= Version::new(major, minor, 0) - } - - /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`, - /// if the current `rustc` is at least that version. - pub fn emit_rustc_version(&self, major: usize, minor: usize) { - if self.probe_rustc_version(major, minor) { - emit(&format!("rustc_{}_{}", major, minor)); - } - } - - fn probe>(&self, code: T) -> Result { - #[allow(deprecated)] - static ID: AtomicUsize = ATOMIC_USIZE_INIT; - - let id = ID.fetch_add(1, Ordering::Relaxed); - let mut command = Command::new(&self.rustc); - command - .arg("--crate-name") - .arg(format!("probe{}", id)) - .arg("--crate-type=lib") - .arg("--out-dir") - .arg(&self.out_dir) - .arg("--emit=llvm-ir"); - - if let &Some(ref rustflags) = &self.rustflags { - command.args(rustflags); - } - - if let Some(target) = self.target.as_ref() { - command.arg("--target").arg(target); - } - - command.arg("-").stdin(Stdio::piped()); - let mut child = try!(command.spawn().map_err(error::from_io)); - let mut stdin = child.stdin.take().expect("rustc stdin"); - - if self.no_std { - try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io)); - } - try!(stdin.write_all(code.as_ref()).map_err(error::from_io)); - drop(stdin); - - let status = try!(child.wait().map_err(error::from_io)); - Ok(status.success()) - } - - /// Tests whether the given sysroot crate can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// extern crate CRATE as probe; - /// ``` - pub fn probe_sysroot_crate(&self, name: &str) -> bool { - self.probe(format!("extern crate {} as probe;", name)) // `as _` wasn't stabilized until Rust 1.33 - .unwrap_or(false) - } - - /// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true. - pub fn emit_sysroot_crate(&self, name: &str) { - if self.probe_sysroot_crate(name) { - emit(&format!("has_{}", mangle(name))); - } - } - - /// Tests whether the given path can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub use PATH; - /// ``` - pub fn probe_path(&self, path: &str) -> bool { - self.probe(format!("pub use {};", path)).unwrap_or(false) - } - - /// Emits a config value `has_PATH` if `probe_path` returns true. - /// - /// Any non-identifier characters in the `path` will be replaced with - /// `_` in the generated config value. - pub fn emit_has_path(&self, path: &str) { - if self.probe_path(path) { - emit(&format!("has_{}", mangle(path))); - } - } - - /// Emits the given `cfg` value if `probe_path` returns true. - pub fn emit_path_cfg(&self, path: &str, cfg: &str) { - if self.probe_path(path) { - emit(cfg); - } - } - - /// Tests whether the given trait can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub trait Probe: TRAIT + Sized {} - /// ``` - pub fn probe_trait(&self, name: &str) -> bool { - self.probe(format!("pub trait Probe: {} + Sized {{}}", name)) - .unwrap_or(false) - } - - /// Emits a config value `has_TRAIT` if `probe_trait` returns true. - /// - /// Any non-identifier characters in the trait `name` will be replaced with - /// `_` in the generated config value. - pub fn emit_has_trait(&self, name: &str) { - if self.probe_trait(name) { - emit(&format!("has_{}", mangle(name))); - } - } - - /// Emits the given `cfg` value if `probe_trait` returns true. - pub fn emit_trait_cfg(&self, name: &str, cfg: &str) { - if self.probe_trait(name) { - emit(cfg); - } - } - - /// Tests whether the given type can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub type Probe = TYPE; - /// ``` - pub fn probe_type(&self, name: &str) -> bool { - self.probe(format!("pub type Probe = {};", name)) - .unwrap_or(false) - } - - /// Emits a config value `has_TYPE` if `probe_type` returns true. - /// - /// Any non-identifier characters in the type `name` will be replaced with - /// `_` in the generated config value. - pub fn emit_has_type(&self, name: &str) { - if self.probe_type(name) { - emit(&format!("has_{}", mangle(name))); - } - } - - /// Emits the given `cfg` value if `probe_type` returns true. - pub fn emit_type_cfg(&self, name: &str, cfg: &str) { - if self.probe_type(name) { - emit(cfg); - } - } -} - -fn mangle(s: &str) -> String { - s.chars() - .map(|c| match c { - 'A'...'Z' | 'a'...'z' | '0'...'9' => c, - _ => '_', - }) - .collect() -} diff --git a/third_party/cargo/vendor/autocfg-0.1.7/src/tests.rs b/third_party/cargo/vendor/autocfg-0.1.7/src/tests.rs deleted file mode 100644 index 304d989..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/src/tests.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::AutoCfg; - -impl AutoCfg { - fn core_std(&self, path: &str) -> String { - let krate = if self.no_std { "core" } else { "std" }; - format!("{}::{}", krate, path) - } -} - -#[test] -fn autocfg_version() { - let ac = AutoCfg::with_dir("target").unwrap(); - println!("version: {:?}", ac.rustc_version); - assert!(ac.probe_rustc_version(1, 0)); -} - -#[test] -fn version_cmp() { - use super::version::Version; - let v123 = Version::new(1, 2, 3); - - assert!(Version::new(1, 0, 0) < v123); - assert!(Version::new(1, 2, 2) < v123); - assert!(Version::new(1, 2, 3) == v123); - assert!(Version::new(1, 2, 4) > v123); - assert!(Version::new(1, 10, 0) > v123); - assert!(Version::new(2, 0, 0) > v123); -} - -#[test] -fn probe_add() { - let ac = AutoCfg::with_dir("target").unwrap(); - let add = ac.core_std("ops::Add"); - let add_rhs = ac.core_std("ops::Add"); - let add_rhs_output = ac.core_std("ops::Add"); - assert!(ac.probe_path(&add)); - assert!(ac.probe_trait(&add)); - assert!(ac.probe_trait(&add_rhs)); - assert!(ac.probe_trait(&add_rhs_output)); - assert!(ac.probe_type(&add_rhs_output)); -} - -#[test] -fn probe_as_ref() { - let ac = AutoCfg::with_dir("target").unwrap(); - let as_ref = ac.core_std("convert::AsRef"); - let as_ref_str = ac.core_std("convert::AsRef"); - assert!(ac.probe_path(&as_ref)); - assert!(ac.probe_trait(&as_ref_str)); - assert!(ac.probe_type(&as_ref_str)); -} - -#[test] -fn probe_i128() { - let ac = AutoCfg::with_dir("target").unwrap(); - let missing = !ac.probe_rustc_version(1, 26); - let i128_path = ac.core_std("i128"); - assert!(missing ^ ac.probe_path(&i128_path)); - assert!(missing ^ ac.probe_type("i128")); -} - -#[test] -fn probe_sum() { - let ac = AutoCfg::with_dir("target").unwrap(); - let missing = !ac.probe_rustc_version(1, 12); - let sum = ac.core_std("iter::Sum"); - let sum_i32 = ac.core_std("iter::Sum"); - assert!(missing ^ ac.probe_path(&sum)); - assert!(missing ^ ac.probe_trait(&sum)); - assert!(missing ^ ac.probe_trait(&sum_i32)); - assert!(missing ^ ac.probe_type(&sum_i32)); -} - -#[test] -fn probe_std() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert_eq!(ac.probe_sysroot_crate("std"), !ac.no_std); -} - -#[test] -fn probe_alloc() { - let ac = AutoCfg::with_dir("target").unwrap(); - let missing = !ac.probe_rustc_version(1, 36); - assert!(missing ^ ac.probe_sysroot_crate("alloc")); -} - -#[test] -fn probe_bad_sysroot_crate() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert!(!ac.probe_sysroot_crate("doesnt_exist")); -} - -#[test] -fn probe_no_std() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert!(ac.probe_type("i32")); - assert!(ac.probe_type("[i32]")); - assert_eq!(ac.probe_type("Vec"), !ac.no_std); -} diff --git a/third_party/cargo/vendor/autocfg-0.1.7/tests/rustflags.rs b/third_party/cargo/vendor/autocfg-0.1.7/tests/rustflags.rs deleted file mode 100644 index bfa0f03..0000000 --- a/third_party/cargo/vendor/autocfg-0.1.7/tests/rustflags.rs +++ /dev/null @@ -1,13 +0,0 @@ -extern crate autocfg; - -/// Tests that autocfg uses the RUSTFLAGS environment variable when running -/// rustc. -#[test] -fn test_with_sysroot() { - std::env::set_var("RUSTFLAGS", "-L target/debug/deps -L target/debug"); - std::env::set_var("OUT_DIR", "target"); - // Ensure HOST != TARGET. - std::env::set_var("HOST", "lol"); - let ac = autocfg::AutoCfg::new().unwrap(); - assert!(ac.probe_sysroot_crate("autocfg")); -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/.cargo-checksum.json b/third_party/cargo/vendor/autocfg-1.0.0/.cargo-checksum.json deleted file mode 100644 index eb0d565..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"8dc9b28e55bc55e1846909cfbb169aef0ff15bef2cfa6e27eef5adb7634eed1a","Cargo.toml":"9a97fd6cdf41c7b507d2d8954f99dbbae3450e9e67934c87e5cabe8fa795f6c5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"f173253f205c245806e5dd16ad1906e1a1b3f89694890236298b2126e937324a","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"4e80b48869f038be4e80e3356e4cce7e81713717ceeca095f9bb04cda2e4d224","src/tests.rs":"8197b5a6e91872d6c63731ed4b7b619068b6d13501d9aecb3652f20857edc9aa","src/version.rs":"175727d5f02f2fe2271ddc9b041db2a5b9c6fe0f95afd17c73a4d982612764a3","tests/rustflags.rs":"441fb0c6606e243c31d3817a5ae2240b65fcae0ea8ab583f80f8f6d6c267e614"},"package":"f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"} \ No newline at end of file diff --git a/third_party/cargo/vendor/autocfg-1.0.0/BUILD.bazel b/third_party/cargo/vendor/autocfg-1.0.0/BUILD.bazel deleted file mode 100644 index 4e4e103..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/BUILD.bazel +++ /dev/null @@ -1,63 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # Apache-2.0 from expression "Apache-2.0 OR MIT" -]) - -# Generated Targets - -# Unsupported target "integers" with type "example" omitted - -# Unsupported target "paths" with type "example" omitted - -# Unsupported target "traits" with type "example" omitted - -# Unsupported target "versions" with type "example" omitted - -rust_library( - name = "autocfg", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.0.0", - # buildifier: leave-alone - deps = [ - ], -) - -# Unsupported target "rustflags" with type "test" omitted diff --git a/third_party/cargo/vendor/autocfg-1.0.0/Cargo.lock b/third_party/cargo/vendor/autocfg-1.0.0/Cargo.lock deleted file mode 100644 index 4f2c78d..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "1.0.0" - diff --git a/third_party/cargo/vendor/autocfg-1.0.0/Cargo.toml b/third_party/cargo/vendor/autocfg-1.0.0/Cargo.toml deleted file mode 100644 index 7ba9df6..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "autocfg" -version = "1.0.0" -authors = ["Josh Stone "] -description = "Automatic cfg for Rust compiler features" -readme = "README.md" -keywords = ["rustc", "build", "autoconf"] -categories = ["development-tools::build-utils"] -license = "Apache-2.0 OR MIT" -repository = "https://github.com/cuviper/autocfg" - -[dependencies] diff --git a/third_party/cargo/vendor/autocfg-1.0.0/LICENSE-MIT b/third_party/cargo/vendor/autocfg-1.0.0/LICENSE-MIT deleted file mode 100644 index 44fbc4d..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2018 Josh Stone - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/third_party/cargo/vendor/autocfg-1.0.0/README.md b/third_party/cargo/vendor/autocfg-1.0.0/README.md deleted file mode 100644 index 5698b0d..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/README.md +++ /dev/null @@ -1,89 +0,0 @@ -autocfg -======= - -[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg) -[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg) -![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg) -[![Travis Status](https://travis-ci.org/cuviper/autocfg.svg?branch=master)](https://travis-ci.org/cuviper/autocfg) - -A Rust library for build scripts to automatically configure code based on -compiler support. Code snippets are dynamically tested to see if the `rustc` -will accept them, rather than hard-coding specific version support. - - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[build-dependencies] -autocfg = "1" -``` - -Then use it in your `build.rs` script to detect compiler features. For -example, to test for 128-bit integer support, it might look like: - -```rust -extern crate autocfg; - -fn main() { - let ac = autocfg::new(); - ac.emit_has_type("i128"); - - // (optional) We don't need to rerun for anything external. - autocfg::rerun_path("build.rs"); -} -``` - -If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line -for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the -rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that -should only be used when the compiler supports it. - - -## Release Notes - -- 1.0.0 (2020-01-08) - - 🎉 Release 1.0! 🎉 (no breaking changes) - - Add `probe_expression` and `emit_expression_cfg` to test arbitrary expressions. - - Add `probe_constant` and `emit_constant_cfg` to test arbitrary constant expressions. - -- 0.1.7 (2019-10-20) - - Apply `RUSTFLAGS` when probing `$TARGET != $HOST`, mainly for sysroot, by @roblabla. - -- 0.1.6 (2019-08-19) - - Add `probe`/`emit_sysroot_crate`, by @leo60228. - -- 0.1.5 (2019-07-16) - - Mask some warnings from newer rustc. - -- 0.1.4 (2019-05-22) - - Relax `std`/`no_std` probing to a warning instead of an error. - - Improve `rustc` bootstrap compatibility. - -- 0.1.3 (2019-05-21) - - Auto-detects if `#![no_std]` is needed for the `$TARGET`. - -- 0.1.2 (2019-01-16) - - Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV`. - - Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH`. - - -## Minimum Rust version policy - -This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is -its entire reason for existence, so this crate will be extremely conservative -about raising this requirement. If this is ever deemed necessary, it will be -treated as a major breaking change for semver purposes. - - -## License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. diff --git a/third_party/cargo/vendor/autocfg-1.0.0/examples/integers.rs b/third_party/cargo/vendor/autocfg-1.0.0/examples/integers.rs deleted file mode 100644 index 23d4cba..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/examples/integers.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern crate autocfg; - -fn main() { - // Normally, cargo will set `OUT_DIR` for build scripts. - let ac = autocfg::AutoCfg::with_dir("target").unwrap(); - for i in 3..8 { - ac.emit_has_type(&format!("i{}", 1 << i)); - } -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/examples/paths.rs b/third_party/cargo/vendor/autocfg-1.0.0/examples/paths.rs deleted file mode 100644 index b7a6ca7..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/examples/paths.rs +++ /dev/null @@ -1,22 +0,0 @@ -extern crate autocfg; - -fn main() { - // Normally, cargo will set `OUT_DIR` for build scripts. - let ac = autocfg::AutoCfg::with_dir("target").unwrap(); - - // since ancient times... - ac.emit_has_path("std::vec::Vec"); - ac.emit_path_cfg("std::vec::Vec", "has_vec"); - - // rustc 1.10.0 - ac.emit_has_path("std::panic::PanicInfo"); - ac.emit_path_cfg("std::panic::PanicInfo", "has_panic_info"); - - // rustc 1.20.0 - ac.emit_has_path("std::mem::ManuallyDrop"); - ac.emit_path_cfg("std::mem::ManuallyDrop", "has_manually_drop"); - - // rustc 1.25.0 - ac.emit_has_path("std::ptr::NonNull"); - ac.emit_path_cfg("std::ptr::NonNull", "has_non_null"); -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/examples/traits.rs b/third_party/cargo/vendor/autocfg-1.0.0/examples/traits.rs deleted file mode 100644 index c1ca003..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/examples/traits.rs +++ /dev/null @@ -1,26 +0,0 @@ -extern crate autocfg; - -fn main() { - // Normally, cargo will set `OUT_DIR` for build scripts. - let ac = autocfg::AutoCfg::with_dir("target").unwrap(); - - // since ancient times... - ac.emit_has_trait("std::ops::Add"); - ac.emit_trait_cfg("std::ops::Add", "has_ops"); - - // trait parameters have to be provided - ac.emit_has_trait("std::borrow::Borrow"); - ac.emit_trait_cfg("std::borrow::Borrow", "has_borrow"); - - // rustc 1.8.0 - ac.emit_has_trait("std::ops::AddAssign"); - ac.emit_trait_cfg("std::ops::AddAssign", "has_assign_ops"); - - // rustc 1.12.0 - ac.emit_has_trait("std::iter::Sum"); - ac.emit_trait_cfg("std::iter::Sum", "has_sum"); - - // rustc 1.28.0 - ac.emit_has_trait("std::alloc::GlobalAlloc"); - ac.emit_trait_cfg("std::alloc::GlobalAlloc", "has_global_alloc"); -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/examples/versions.rs b/third_party/cargo/vendor/autocfg-1.0.0/examples/versions.rs deleted file mode 100644 index 992919b..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/examples/versions.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern crate autocfg; - -fn main() { - // Normally, cargo will set `OUT_DIR` for build scripts. - let ac = autocfg::AutoCfg::with_dir("target").unwrap(); - for i in 0..100 { - ac.emit_rustc_version(1, i); - } -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/src/error.rs b/third_party/cargo/vendor/autocfg-1.0.0/src/error.rs deleted file mode 100644 index 4624835..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/src/error.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::error; -use std::fmt; -use std::io; -use std::num; -use std::str; - -/// A common error type for the `autocfg` crate. -#[derive(Debug)] -pub struct Error { - kind: ErrorKind, -} - -impl error::Error for Error { - fn description(&self) -> &str { - "AutoCfg error" - } - - fn cause(&self) -> Option<&error::Error> { - match self.kind { - ErrorKind::Io(ref e) => Some(e), - ErrorKind::Num(ref e) => Some(e), - ErrorKind::Utf8(ref e) => Some(e), - ErrorKind::Other(_) => None, - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match self.kind { - ErrorKind::Io(ref e) => e.fmt(f), - ErrorKind::Num(ref e) => e.fmt(f), - ErrorKind::Utf8(ref e) => e.fmt(f), - ErrorKind::Other(s) => s.fmt(f), - } - } -} - -#[derive(Debug)] -enum ErrorKind { - Io(io::Error), - Num(num::ParseIntError), - Utf8(str::Utf8Error), - Other(&'static str), -} - -pub fn from_io(e: io::Error) -> Error { - Error { - kind: ErrorKind::Io(e), - } -} - -pub fn from_num(e: num::ParseIntError) -> Error { - Error { - kind: ErrorKind::Num(e), - } -} - -pub fn from_utf8(e: str::Utf8Error) -> Error { - Error { - kind: ErrorKind::Utf8(e), - } -} - -pub fn from_str(s: &'static str) -> Error { - Error { - kind: ErrorKind::Other(s), - } -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/src/lib.rs b/third_party/cargo/vendor/autocfg-1.0.0/src/lib.rs deleted file mode 100644 index a478010..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/src/lib.rs +++ /dev/null @@ -1,412 +0,0 @@ -//! A Rust library for build scripts to automatically configure code based on -//! compiler support. Code snippets are dynamically tested to see if the `rustc` -//! will accept them, rather than hard-coding specific version support. -//! -//! -//! ## Usage -//! -//! Add this to your `Cargo.toml`: -//! -//! ```toml -//! [build-dependencies] -//! autocfg = "1" -//! ``` -//! -//! Then use it in your `build.rs` script to detect compiler features. For -//! example, to test for 128-bit integer support, it might look like: -//! -//! ```rust -//! extern crate autocfg; -//! -//! fn main() { -//! # // Normally, cargo will set `OUT_DIR` for build scripts. -//! # std::env::set_var("OUT_DIR", "target"); -//! let ac = autocfg::new(); -//! ac.emit_has_type("i128"); -//! -//! // (optional) We don't need to rerun for anything external. -//! autocfg::rerun_path("build.rs"); -//! } -//! ``` -//! -//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line -//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the -//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that -//! should only be used when the compiler supports it. -//! -//! ## Caution -//! -//! Many of the probing methods of `AutoCfg` document the particular template they -//! use, **subject to change**. The inputs are not validated to make sure they are -//! semantically correct for their expected use, so it's _possible_ to escape and -//! inject something unintended. However, such abuse is unsupported and will not -//! be considered when making changes to the templates. - -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -// allow future warnings that can't be fixed while keeping 1.0 compatibility -#![allow(unknown_lints)] -#![allow(bare_trait_objects)] -#![allow(ellipsis_inclusive_range_patterns)] - -/// Local macro to avoid `std::try!`, deprecated in Rust 1.39. -macro_rules! try { - ($result:expr) => { - match $result { - Ok(value) => value, - Err(error) => return Err(error), - } - }; -} - -use std::env; -use std::ffi::OsString; -use std::fs; -use std::io::{stderr, Write}; -use std::path::PathBuf; -use std::process::{Command, Stdio}; -#[allow(deprecated)] -use std::sync::atomic::ATOMIC_USIZE_INIT; -use std::sync::atomic::{AtomicUsize, Ordering}; - -mod error; -pub use error::Error; - -mod version; -use version::Version; - -#[cfg(test)] -mod tests; - -/// Helper to detect compiler features for `cfg` output in build scripts. -#[derive(Clone, Debug)] -pub struct AutoCfg { - out_dir: PathBuf, - rustc: PathBuf, - rustc_version: Version, - target: Option, - no_std: bool, - rustflags: Option>, -} - -/// Writes a config flag for rustc on standard out. -/// -/// This looks like: `cargo:rustc-cfg=CFG` -/// -/// Cargo will use this in arguments to rustc, like `--cfg CFG`. -pub fn emit(cfg: &str) { - println!("cargo:rustc-cfg={}", cfg); -} - -/// Writes a line telling Cargo to rerun the build script if `path` changes. -/// -/// This looks like: `cargo:rerun-if-changed=PATH` -/// -/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier -/// versions of cargo will simply ignore the directive. -pub fn rerun_path(path: &str) { - println!("cargo:rerun-if-changed={}", path); -} - -/// Writes a line telling Cargo to rerun the build script if the environment -/// variable `var` changes. -/// -/// This looks like: `cargo:rerun-if-env-changed=VAR` -/// -/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier -/// versions of cargo will simply ignore the directive. -pub fn rerun_env(var: &str) { - println!("cargo:rerun-if-env-changed={}", var); -} - -/// Create a new `AutoCfg` instance. -/// -/// # Panics -/// -/// Panics if `AutoCfg::new()` returns an error. -pub fn new() -> AutoCfg { - AutoCfg::new().unwrap() -} - -impl AutoCfg { - /// Create a new `AutoCfg` instance. - /// - /// # Common errors - /// - /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. - /// - The version output from `rustc` can't be parsed. - /// - `OUT_DIR` is not set in the environment, or is not a writable directory. - /// - pub fn new() -> Result { - match env::var_os("OUT_DIR") { - Some(d) => Self::with_dir(d), - None => Err(error::from_str("no OUT_DIR specified!")), - } - } - - /// Create a new `AutoCfg` instance with the specified output directory. - /// - /// # Common errors - /// - /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. - /// - The version output from `rustc` can't be parsed. - /// - `dir` is not a writable directory. - /// - pub fn with_dir>(dir: T) -> Result { - let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); - let rustc: PathBuf = rustc.into(); - let rustc_version = try!(Version::from_rustc(&rustc)); - - // Sanity check the output directory - let dir = dir.into(); - let meta = try!(fs::metadata(&dir).map_err(error::from_io)); - if !meta.is_dir() || meta.permissions().readonly() { - return Err(error::from_str("output path is not a writable directory")); - } - - // Cargo only applies RUSTFLAGS for building TARGET artifact in - // cross-compilation environment. Sadly, we don't have a way to detect - // when we're building HOST artifact in a cross-compilation environment, - // so for now we only apply RUSTFLAGS when cross-compiling an artifact. - // - // See https://github.com/cuviper/autocfg/pull/10#issuecomment-527575030. - let rustflags = if env::var_os("TARGET") != env::var_os("HOST") { - env::var("RUSTFLAGS").ok().map(|rustflags| { - // This is meant to match how cargo handles the RUSTFLAG environment - // variable. - // See https://github.com/rust-lang/cargo/blob/69aea5b6f69add7c51cca939a79644080c0b0ba0/src/cargo/core/compiler/build_context/target_info.rs#L434-L441 - rustflags - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(str::to_string) - .collect::>() - }) - } else { - None - }; - - let mut ac = AutoCfg { - out_dir: dir, - rustc: rustc, - rustc_version: rustc_version, - target: env::var_os("TARGET"), - no_std: false, - rustflags: rustflags, - }; - - // Sanity check with and without `std`. - if !ac.probe("").unwrap_or(false) { - ac.no_std = true; - if !ac.probe("").unwrap_or(false) { - // Neither worked, so assume nothing... - ac.no_std = false; - let warning = b"warning: autocfg could not probe for `std`\n"; - stderr().write_all(warning).ok(); - } - } - Ok(ac) - } - - /// Test whether the current `rustc` reports a version greater than - /// or equal to "`major`.`minor`". - pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool { - self.rustc_version >= Version::new(major, minor, 0) - } - - /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`, - /// if the current `rustc` is at least that version. - pub fn emit_rustc_version(&self, major: usize, minor: usize) { - if self.probe_rustc_version(major, minor) { - emit(&format!("rustc_{}_{}", major, minor)); - } - } - - fn probe>(&self, code: T) -> Result { - #[allow(deprecated)] - static ID: AtomicUsize = ATOMIC_USIZE_INIT; - - let id = ID.fetch_add(1, Ordering::Relaxed); - let mut command = Command::new(&self.rustc); - command - .arg("--crate-name") - .arg(format!("probe{}", id)) - .arg("--crate-type=lib") - .arg("--out-dir") - .arg(&self.out_dir) - .arg("--emit=llvm-ir"); - - if let &Some(ref rustflags) = &self.rustflags { - command.args(rustflags); - } - - if let Some(target) = self.target.as_ref() { - command.arg("--target").arg(target); - } - - command.arg("-").stdin(Stdio::piped()); - let mut child = try!(command.spawn().map_err(error::from_io)); - let mut stdin = child.stdin.take().expect("rustc stdin"); - - if self.no_std { - try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io)); - } - try!(stdin.write_all(code.as_ref()).map_err(error::from_io)); - drop(stdin); - - let status = try!(child.wait().map_err(error::from_io)); - Ok(status.success()) - } - - /// Tests whether the given sysroot crate can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// extern crate CRATE as probe; - /// ``` - pub fn probe_sysroot_crate(&self, name: &str) -> bool { - self.probe(format!("extern crate {} as probe;", name)) // `as _` wasn't stabilized until Rust 1.33 - .unwrap_or(false) - } - - /// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true. - pub fn emit_sysroot_crate(&self, name: &str) { - if self.probe_sysroot_crate(name) { - emit(&format!("has_{}", mangle(name))); - } - } - - /// Tests whether the given path can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub use PATH; - /// ``` - pub fn probe_path(&self, path: &str) -> bool { - self.probe(format!("pub use {};", path)).unwrap_or(false) - } - - /// Emits a config value `has_PATH` if `probe_path` returns true. - /// - /// Any non-identifier characters in the `path` will be replaced with - /// `_` in the generated config value. - pub fn emit_has_path(&self, path: &str) { - if self.probe_path(path) { - emit(&format!("has_{}", mangle(path))); - } - } - - /// Emits the given `cfg` value if `probe_path` returns true. - pub fn emit_path_cfg(&self, path: &str, cfg: &str) { - if self.probe_path(path) { - emit(cfg); - } - } - - /// Tests whether the given trait can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub trait Probe: TRAIT + Sized {} - /// ``` - pub fn probe_trait(&self, name: &str) -> bool { - self.probe(format!("pub trait Probe: {} + Sized {{}}", name)) - .unwrap_or(false) - } - - /// Emits a config value `has_TRAIT` if `probe_trait` returns true. - /// - /// Any non-identifier characters in the trait `name` will be replaced with - /// `_` in the generated config value. - pub fn emit_has_trait(&self, name: &str) { - if self.probe_trait(name) { - emit(&format!("has_{}", mangle(name))); - } - } - - /// Emits the given `cfg` value if `probe_trait` returns true. - pub fn emit_trait_cfg(&self, name: &str, cfg: &str) { - if self.probe_trait(name) { - emit(cfg); - } - } - - /// Tests whether the given type can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub type Probe = TYPE; - /// ``` - pub fn probe_type(&self, name: &str) -> bool { - self.probe(format!("pub type Probe = {};", name)) - .unwrap_or(false) - } - - /// Emits a config value `has_TYPE` if `probe_type` returns true. - /// - /// Any non-identifier characters in the type `name` will be replaced with - /// `_` in the generated config value. - pub fn emit_has_type(&self, name: &str) { - if self.probe_type(name) { - emit(&format!("has_{}", mangle(name))); - } - } - - /// Emits the given `cfg` value if `probe_type` returns true. - pub fn emit_type_cfg(&self, name: &str, cfg: &str) { - if self.probe_type(name) { - emit(cfg); - } - } - - /// Tests whether the given expression can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub fn probe() { let _ = EXPR; } - /// ``` - pub fn probe_expression(&self, expr: &str) -> bool { - self.probe(format!("pub fn probe() {{ let _ = {}; }}", expr)) - .unwrap_or(false) - } - - /// Emits the given `cfg` value if `probe_expression` returns true. - pub fn emit_expression_cfg(&self, expr: &str, cfg: &str) { - if self.probe_expression(expr) { - emit(cfg); - } - } - - /// Tests whether the given constant expression can be used. - /// - /// The test code is subject to change, but currently looks like: - /// - /// ```ignore - /// pub const PROBE: () = ((), EXPR).0; - /// ``` - pub fn probe_constant(&self, expr: &str) -> bool { - self.probe(format!("pub const PROBE: () = ((), {}).0;", expr)) - .unwrap_or(false) - } - - /// Emits the given `cfg` value if `probe_constant` returns true. - pub fn emit_constant_cfg(&self, expr: &str, cfg: &str) { - if self.probe_constant(expr) { - emit(cfg); - } - } -} - -fn mangle(s: &str) -> String { - s.chars() - .map(|c| match c { - 'A'...'Z' | 'a'...'z' | '0'...'9' => c, - _ => '_', - }) - .collect() -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/src/tests.rs b/third_party/cargo/vendor/autocfg-1.0.0/src/tests.rs deleted file mode 100644 index f558e71..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/src/tests.rs +++ /dev/null @@ -1,125 +0,0 @@ -use super::AutoCfg; - -impl AutoCfg { - fn core_std(&self, path: &str) -> String { - let krate = if self.no_std { "core" } else { "std" }; - format!("{}::{}", krate, path) - } - - fn assert_std(&self, probe_result: bool) { - assert_eq!(!self.no_std, probe_result); - } - - fn assert_min(&self, major: usize, minor: usize, probe_result: bool) { - assert_eq!(self.probe_rustc_version(major, minor), probe_result); - } -} - -#[test] -fn autocfg_version() { - let ac = AutoCfg::with_dir("target").unwrap(); - println!("version: {:?}", ac.rustc_version); - assert!(ac.probe_rustc_version(1, 0)); -} - -#[test] -fn version_cmp() { - use super::version::Version; - let v123 = Version::new(1, 2, 3); - - assert!(Version::new(1, 0, 0) < v123); - assert!(Version::new(1, 2, 2) < v123); - assert!(Version::new(1, 2, 3) == v123); - assert!(Version::new(1, 2, 4) > v123); - assert!(Version::new(1, 10, 0) > v123); - assert!(Version::new(2, 0, 0) > v123); -} - -#[test] -fn probe_add() { - let ac = AutoCfg::with_dir("target").unwrap(); - let add = ac.core_std("ops::Add"); - let add_rhs = add.clone() + ""; - let add_rhs_output = add.clone() + ""; - let dyn_add_rhs_output = "dyn ".to_string() + &*add_rhs_output; - assert!(ac.probe_path(&add)); - assert!(ac.probe_trait(&add)); - assert!(ac.probe_trait(&add_rhs)); - assert!(ac.probe_trait(&add_rhs_output)); - ac.assert_min(1, 27, ac.probe_type(&dyn_add_rhs_output)); -} - -#[test] -fn probe_as_ref() { - let ac = AutoCfg::with_dir("target").unwrap(); - let as_ref = ac.core_std("convert::AsRef"); - let as_ref_str = as_ref.clone() + ""; - let dyn_as_ref_str = "dyn ".to_string() + &*as_ref_str; - assert!(ac.probe_path(&as_ref)); - assert!(ac.probe_trait(&as_ref_str)); - assert!(ac.probe_type(&as_ref_str)); - ac.assert_min(1, 27, ac.probe_type(&dyn_as_ref_str)); -} - -#[test] -fn probe_i128() { - let ac = AutoCfg::with_dir("target").unwrap(); - let i128_path = ac.core_std("i128"); - ac.assert_min(1, 26, ac.probe_path(&i128_path)); - ac.assert_min(1, 26, ac.probe_type("i128")); -} - -#[test] -fn probe_sum() { - let ac = AutoCfg::with_dir("target").unwrap(); - let sum = ac.core_std("iter::Sum"); - let sum_i32 = sum.clone() + ""; - let dyn_sum_i32 = "dyn ".to_string() + &*sum_i32; - ac.assert_min(1, 12, ac.probe_path(&sum)); - ac.assert_min(1, 12, ac.probe_trait(&sum)); - ac.assert_min(1, 12, ac.probe_trait(&sum_i32)); - ac.assert_min(1, 12, ac.probe_type(&sum_i32)); - ac.assert_min(1, 27, ac.probe_type(&dyn_sum_i32)); -} - -#[test] -fn probe_std() { - let ac = AutoCfg::with_dir("target").unwrap(); - ac.assert_std(ac.probe_sysroot_crate("std")); -} - -#[test] -fn probe_alloc() { - let ac = AutoCfg::with_dir("target").unwrap(); - ac.assert_min(1, 36, ac.probe_sysroot_crate("alloc")); -} - -#[test] -fn probe_bad_sysroot_crate() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert!(!ac.probe_sysroot_crate("doesnt_exist")); -} - -#[test] -fn probe_no_std() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert!(ac.probe_type("i32")); - assert!(ac.probe_type("[i32]")); - ac.assert_std(ac.probe_type("Vec")); -} - -#[test] -fn probe_expression() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert!(ac.probe_expression(r#""test".trim_left()"#)); - ac.assert_min(1, 30, ac.probe_expression(r#""test".trim_start()"#)); - ac.assert_std(ac.probe_expression("[1, 2, 3].to_vec()")); -} - -#[test] -fn probe_constant() { - let ac = AutoCfg::with_dir("target").unwrap(); - assert!(ac.probe_constant("1 + 2 + 3")); - ac.assert_min(1, 33, ac.probe_constant("{ let x = 1 + 2 + 3; x * x }")); - ac.assert_min(1, 39, ac.probe_constant(r#""test".len()"#)); -} diff --git a/third_party/cargo/vendor/autocfg-1.0.0/src/version.rs b/third_party/cargo/vendor/autocfg-1.0.0/src/version.rs deleted file mode 100644 index 378c21e..0000000 --- a/third_party/cargo/vendor/autocfg-1.0.0/src/version.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::path::Path; -use std::process::Command; -use std::str; - -use super::{error, Error}; - -/// A version structure for making relative comparisons. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Version { - major: usize, - minor: usize, - patch: usize, -} - -impl Version { - /// Creates a `Version` instance for a specific `major.minor.patch` version. - pub fn new(major: usize, minor: usize, patch: usize) -> Self { - Version { - major: major, - minor: minor, - patch: patch, - } - } - - pub fn from_rustc(rustc: &Path) -> Result { - // Get rustc's verbose version - let output = try!(Command::new(rustc) - .args(&["--version", "--verbose"]) - .output() - .map_err(error::from_io)); - if !output.status.success() { - return Err(error::from_str("could not execute rustc")); - } - let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8)); - - // Find the release line in the verbose version output. - let release = match output.lines().find(|line| line.starts_with("release: ")) { - Some(line) => &line["release: ".len()..], - None => return Err(error::from_str("could not find rustc release")), - }; - - // Strip off any extra channel info, e.g. "-beta.N", "-nightly" - let version = match release.find('-') { - Some(i) => &release[..i], - None => release, - }; - - // Split the version into semver components. - let mut iter = version.splitn(3, '.'); - let major = try!(iter.next().ok_or(error::from_str("missing major version"))); - let minor = try!(iter.next().ok_or(error::from_str("missing minor version"))); - let patch = try!(iter.next().ok_or(error::from_str("missing patch version"))); - - Ok(Version::new( - try!(major.parse().map_err(error::from_num)), - try!(minor.parse().map_err(error::from_num)), - try!(patch.parse().map_err(error::from_num)), - )) - } -} diff --git a/third_party/cargo/vendor/autocfg-1.0.1/.cargo-checksum.json b/third_party/cargo/vendor/autocfg-1.0.1/.cargo-checksum.json new file mode 100644 index 0000000..c8e262a --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"d658acfaa27a2b30de98cf004d4d3f4ec0f1757b136610289cbbd1c847ae2e6c","Cargo.toml":"e2176be78c2989884eba4a20a58a672277b3a8a99a72b0ba7347f48eb827ae0e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"2d8b6f07819ad7adfab1d153216bfdcde154ffd4a870d98794125c910b0f4593","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"9b450d90730624807979045ea7ff48374355314cd894345e1b9651485ba1b2ff","src/tests.rs":"a902fbd42b0f0b81a2830f2368fab733041b02fcb902c8e2520d07b3bff10713","src/version.rs":"175727d5f02f2fe2271ddc9b041db2a5b9c6fe0f95afd17c73a4d982612764a3","tests/rustflags.rs":"441fb0c6606e243c31d3817a5ae2240b65fcae0ea8ab583f80f8f6d6c267e614"},"package":"cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"} \ No newline at end of file diff --git a/third_party/cargo/vendor/autocfg-1.0.1/BUILD.bazel b/third_party/cargo/vendor/autocfg-1.0.1/BUILD.bazel new file mode 100644 index 0000000..38981fb --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/BUILD.bazel @@ -0,0 +1,63 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Apache-2.0 from expression "Apache-2.0 OR MIT" +]) + +# Generated Targets + +# Unsupported target "integers" with type "example" omitted + +# Unsupported target "paths" with type "example" omitted + +# Unsupported target "traits" with type "example" omitted + +# Unsupported target "versions" with type "example" omitted + +rust_library( + name = "autocfg", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.0.1", + # buildifier: leave-alone + deps = [ + ], +) + +# Unsupported target "rustflags" with type "test" omitted diff --git a/third_party/cargo/vendor/autocfg-1.0.1/Cargo.lock b/third_party/cargo/vendor/autocfg-1.0.1/Cargo.lock new file mode 100644 index 0000000..a2d1343 --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.1" + diff --git a/third_party/cargo/vendor/autocfg-1.0.1/Cargo.toml b/third_party/cargo/vendor/autocfg-1.0.1/Cargo.toml new file mode 100644 index 0000000..7adf795 --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "autocfg" +version = "1.0.1" +authors = ["Josh Stone "] +exclude = ["/.github/**", "/bors.toml"] +description = "Automatic cfg for Rust compiler features" +readme = "README.md" +keywords = ["rustc", "build", "autoconf"] +categories = ["development-tools::build-utils"] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/cuviper/autocfg" + +[dependencies] diff --git a/third_party/cargo/vendor/autocfg-0.1.7/LICENSE-APACHE b/third_party/cargo/vendor/autocfg-1.0.1/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/LICENSE-APACHE rename to third_party/cargo/vendor/autocfg-1.0.1/LICENSE-APACHE diff --git a/third_party/cargo/vendor/autocfg-0.1.7/LICENSE-MIT b/third_party/cargo/vendor/autocfg-1.0.1/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/LICENSE-MIT rename to third_party/cargo/vendor/autocfg-1.0.1/LICENSE-MIT diff --git a/third_party/cargo/vendor/autocfg-1.0.1/README.md b/third_party/cargo/vendor/autocfg-1.0.1/README.md new file mode 100644 index 0000000..3788161 --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/README.md @@ -0,0 +1,92 @@ +autocfg +======= + +[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg) +[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg) +![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg) +![build status](https://github.com/cuviper/autocfg/workflows/master/badge.svg) + +A Rust library for build scripts to automatically configure code based on +compiler support. Code snippets are dynamically tested to see if the `rustc` +will accept them, rather than hard-coding specific version support. + + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[build-dependencies] +autocfg = "1" +``` + +Then use it in your `build.rs` script to detect compiler features. For +example, to test for 128-bit integer support, it might look like: + +```rust +extern crate autocfg; + +fn main() { + let ac = autocfg::new(); + ac.emit_has_type("i128"); + + // (optional) We don't need to rerun for anything external. + autocfg::rerun_path("build.rs"); +} +``` + +If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line +for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the +rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that +should only be used when the compiler supports it. + + +## Release Notes + +- 1.0.1 (2020-08-20) + - Apply `RUSTFLAGS` for more `--target` scenarios, by @adamreichold. + +- 1.0.0 (2020-01-08) + - 🎉 Release 1.0! 🎉 (no breaking changes) + - Add `probe_expression` and `emit_expression_cfg` to test arbitrary expressions. + - Add `probe_constant` and `emit_constant_cfg` to test arbitrary constant expressions. + +- 0.1.7 (2019-10-20) + - Apply `RUSTFLAGS` when probing `$TARGET != $HOST`, mainly for sysroot, by @roblabla. + +- 0.1.6 (2019-08-19) + - Add `probe`/`emit_sysroot_crate`, by @leo60228. + +- 0.1.5 (2019-07-16) + - Mask some warnings from newer rustc. + +- 0.1.4 (2019-05-22) + - Relax `std`/`no_std` probing to a warning instead of an error. + - Improve `rustc` bootstrap compatibility. + +- 0.1.3 (2019-05-21) + - Auto-detects if `#![no_std]` is needed for the `$TARGET`. + +- 0.1.2 (2019-01-16) + - Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV`. + - Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH`. + + +## Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is +its entire reason for existence, so this crate will be extremely conservative +about raising this requirement. If this is ever deemed necessary, it will be +treated as a major breaking change for semver purposes. + + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. diff --git a/third_party/cargo/vendor/autocfg-0.1.7/examples/integers.rs b/third_party/cargo/vendor/autocfg-1.0.1/examples/integers.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/examples/integers.rs rename to third_party/cargo/vendor/autocfg-1.0.1/examples/integers.rs diff --git a/third_party/cargo/vendor/autocfg-0.1.7/examples/paths.rs b/third_party/cargo/vendor/autocfg-1.0.1/examples/paths.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/examples/paths.rs rename to third_party/cargo/vendor/autocfg-1.0.1/examples/paths.rs diff --git a/third_party/cargo/vendor/autocfg-0.1.7/examples/traits.rs b/third_party/cargo/vendor/autocfg-1.0.1/examples/traits.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/examples/traits.rs rename to third_party/cargo/vendor/autocfg-1.0.1/examples/traits.rs diff --git a/third_party/cargo/vendor/autocfg-0.1.7/examples/versions.rs b/third_party/cargo/vendor/autocfg-1.0.1/examples/versions.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/examples/versions.rs rename to third_party/cargo/vendor/autocfg-1.0.1/examples/versions.rs diff --git a/third_party/cargo/vendor/autocfg-0.1.7/src/error.rs b/third_party/cargo/vendor/autocfg-1.0.1/src/error.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/src/error.rs rename to third_party/cargo/vendor/autocfg-1.0.1/src/error.rs diff --git a/third_party/cargo/vendor/autocfg-1.0.1/src/lib.rs b/third_party/cargo/vendor/autocfg-1.0.1/src/lib.rs new file mode 100644 index 0000000..de50135 --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/src/lib.rs @@ -0,0 +1,438 @@ +//! A Rust library for build scripts to automatically configure code based on +//! compiler support. Code snippets are dynamically tested to see if the `rustc` +//! will accept them, rather than hard-coding specific version support. +//! +//! +//! ## Usage +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! autocfg = "1" +//! ``` +//! +//! Then use it in your `build.rs` script to detect compiler features. For +//! example, to test for 128-bit integer support, it might look like: +//! +//! ```rust +//! extern crate autocfg; +//! +//! fn main() { +//! # // Normally, cargo will set `OUT_DIR` for build scripts. +//! # std::env::set_var("OUT_DIR", "target"); +//! let ac = autocfg::new(); +//! ac.emit_has_type("i128"); +//! +//! // (optional) We don't need to rerun for anything external. +//! autocfg::rerun_path("build.rs"); +//! } +//! ``` +//! +//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line +//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the +//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that +//! should only be used when the compiler supports it. +//! +//! ## Caution +//! +//! Many of the probing methods of `AutoCfg` document the particular template they +//! use, **subject to change**. The inputs are not validated to make sure they are +//! semantically correct for their expected use, so it's _possible_ to escape and +//! inject something unintended. However, such abuse is unsupported and will not +//! be considered when making changes to the templates. + +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] +// allow future warnings that can't be fixed while keeping 1.0 compatibility +#![allow(unknown_lints)] +#![allow(bare_trait_objects)] +#![allow(ellipsis_inclusive_range_patterns)] + +/// Local macro to avoid `std::try!`, deprecated in Rust 1.39. +macro_rules! try { + ($result:expr) => { + match $result { + Ok(value) => value, + Err(error) => return Err(error), + } + }; +} + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io::{stderr, Write}; +use std::path::PathBuf; +use std::process::{Command, Stdio}; +#[allow(deprecated)] +use std::sync::atomic::ATOMIC_USIZE_INIT; +use std::sync::atomic::{AtomicUsize, Ordering}; + +mod error; +pub use error::Error; + +mod version; +use version::Version; + +#[cfg(test)] +mod tests; + +/// Helper to detect compiler features for `cfg` output in build scripts. +#[derive(Clone, Debug)] +pub struct AutoCfg { + out_dir: PathBuf, + rustc: PathBuf, + rustc_version: Version, + target: Option, + no_std: bool, + rustflags: Option>, +} + +/// Writes a config flag for rustc on standard out. +/// +/// This looks like: `cargo:rustc-cfg=CFG` +/// +/// Cargo will use this in arguments to rustc, like `--cfg CFG`. +pub fn emit(cfg: &str) { + println!("cargo:rustc-cfg={}", cfg); +} + +/// Writes a line telling Cargo to rerun the build script if `path` changes. +/// +/// This looks like: `cargo:rerun-if-changed=PATH` +/// +/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier +/// versions of cargo will simply ignore the directive. +pub fn rerun_path(path: &str) { + println!("cargo:rerun-if-changed={}", path); +} + +/// Writes a line telling Cargo to rerun the build script if the environment +/// variable `var` changes. +/// +/// This looks like: `cargo:rerun-if-env-changed=VAR` +/// +/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier +/// versions of cargo will simply ignore the directive. +pub fn rerun_env(var: &str) { + println!("cargo:rerun-if-env-changed={}", var); +} + +/// Create a new `AutoCfg` instance. +/// +/// # Panics +/// +/// Panics if `AutoCfg::new()` returns an error. +pub fn new() -> AutoCfg { + AutoCfg::new().unwrap() +} + +impl AutoCfg { + /// Create a new `AutoCfg` instance. + /// + /// # Common errors + /// + /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. + /// - The version output from `rustc` can't be parsed. + /// - `OUT_DIR` is not set in the environment, or is not a writable directory. + /// + pub fn new() -> Result { + match env::var_os("OUT_DIR") { + Some(d) => Self::with_dir(d), + None => Err(error::from_str("no OUT_DIR specified!")), + } + } + + /// Create a new `AutoCfg` instance with the specified output directory. + /// + /// # Common errors + /// + /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. + /// - The version output from `rustc` can't be parsed. + /// - `dir` is not a writable directory. + /// + pub fn with_dir>(dir: T) -> Result { + let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); + let rustc: PathBuf = rustc.into(); + let rustc_version = try!(Version::from_rustc(&rustc)); + + let target = env::var_os("TARGET"); + + // Sanity check the output directory + let dir = dir.into(); + let meta = try!(fs::metadata(&dir).map_err(error::from_io)); + if !meta.is_dir() || meta.permissions().readonly() { + return Err(error::from_str("output path is not a writable directory")); + } + + // Cargo only applies RUSTFLAGS for building TARGET artifact in + // cross-compilation environment. Sadly, we don't have a way to detect + // when we're building HOST artifact in a cross-compilation environment, + // so for now we only apply RUSTFLAGS when cross-compiling an artifact. + // + // See https://github.com/cuviper/autocfg/pull/10#issuecomment-527575030. + let rustflags = if target != env::var_os("HOST") + || dir_contains_target(&target, &dir, env::var_os("CARGO_TARGET_DIR")) + { + env::var("RUSTFLAGS").ok().map(|rustflags| { + // This is meant to match how cargo handles the RUSTFLAG environment + // variable. + // See https://github.com/rust-lang/cargo/blob/69aea5b6f69add7c51cca939a79644080c0b0ba0/src/cargo/core/compiler/build_context/target_info.rs#L434-L441 + rustflags + .split(' ') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(str::to_string) + .collect::>() + }) + } else { + None + }; + + let mut ac = AutoCfg { + out_dir: dir, + rustc: rustc, + rustc_version: rustc_version, + target: target, + no_std: false, + rustflags: rustflags, + }; + + // Sanity check with and without `std`. + if !ac.probe("").unwrap_or(false) { + ac.no_std = true; + if !ac.probe("").unwrap_or(false) { + // Neither worked, so assume nothing... + ac.no_std = false; + let warning = b"warning: autocfg could not probe for `std`\n"; + stderr().write_all(warning).ok(); + } + } + Ok(ac) + } + + /// Test whether the current `rustc` reports a version greater than + /// or equal to "`major`.`minor`". + pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool { + self.rustc_version >= Version::new(major, minor, 0) + } + + /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`, + /// if the current `rustc` is at least that version. + pub fn emit_rustc_version(&self, major: usize, minor: usize) { + if self.probe_rustc_version(major, minor) { + emit(&format!("rustc_{}_{}", major, minor)); + } + } + + fn probe>(&self, code: T) -> Result { + #[allow(deprecated)] + static ID: AtomicUsize = ATOMIC_USIZE_INIT; + + let id = ID.fetch_add(1, Ordering::Relaxed); + let mut command = Command::new(&self.rustc); + command + .arg("--crate-name") + .arg(format!("probe{}", id)) + .arg("--crate-type=lib") + .arg("--out-dir") + .arg(&self.out_dir) + .arg("--emit=llvm-ir"); + + if let &Some(ref rustflags) = &self.rustflags { + command.args(rustflags); + } + + if let Some(target) = self.target.as_ref() { + command.arg("--target").arg(target); + } + + command.arg("-").stdin(Stdio::piped()); + let mut child = try!(command.spawn().map_err(error::from_io)); + let mut stdin = child.stdin.take().expect("rustc stdin"); + + if self.no_std { + try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io)); + } + try!(stdin.write_all(code.as_ref()).map_err(error::from_io)); + drop(stdin); + + let status = try!(child.wait().map_err(error::from_io)); + Ok(status.success()) + } + + /// Tests whether the given sysroot crate can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// extern crate CRATE as probe; + /// ``` + pub fn probe_sysroot_crate(&self, name: &str) -> bool { + self.probe(format!("extern crate {} as probe;", name)) // `as _` wasn't stabilized until Rust 1.33 + .unwrap_or(false) + } + + /// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true. + pub fn emit_sysroot_crate(&self, name: &str) { + if self.probe_sysroot_crate(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Tests whether the given path can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub use PATH; + /// ``` + pub fn probe_path(&self, path: &str) -> bool { + self.probe(format!("pub use {};", path)).unwrap_or(false) + } + + /// Emits a config value `has_PATH` if `probe_path` returns true. + /// + /// Any non-identifier characters in the `path` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_path(&self, path: &str) { + if self.probe_path(path) { + emit(&format!("has_{}", mangle(path))); + } + } + + /// Emits the given `cfg` value if `probe_path` returns true. + pub fn emit_path_cfg(&self, path: &str, cfg: &str) { + if self.probe_path(path) { + emit(cfg); + } + } + + /// Tests whether the given trait can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub trait Probe: TRAIT + Sized {} + /// ``` + pub fn probe_trait(&self, name: &str) -> bool { + self.probe(format!("pub trait Probe: {} + Sized {{}}", name)) + .unwrap_or(false) + } + + /// Emits a config value `has_TRAIT` if `probe_trait` returns true. + /// + /// Any non-identifier characters in the trait `name` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_trait(&self, name: &str) { + if self.probe_trait(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Emits the given `cfg` value if `probe_trait` returns true. + pub fn emit_trait_cfg(&self, name: &str, cfg: &str) { + if self.probe_trait(name) { + emit(cfg); + } + } + + /// Tests whether the given type can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub type Probe = TYPE; + /// ``` + pub fn probe_type(&self, name: &str) -> bool { + self.probe(format!("pub type Probe = {};", name)) + .unwrap_or(false) + } + + /// Emits a config value `has_TYPE` if `probe_type` returns true. + /// + /// Any non-identifier characters in the type `name` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_type(&self, name: &str) { + if self.probe_type(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Emits the given `cfg` value if `probe_type` returns true. + pub fn emit_type_cfg(&self, name: &str, cfg: &str) { + if self.probe_type(name) { + emit(cfg); + } + } + + /// Tests whether the given expression can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub fn probe() { let _ = EXPR; } + /// ``` + pub fn probe_expression(&self, expr: &str) -> bool { + self.probe(format!("pub fn probe() {{ let _ = {}; }}", expr)) + .unwrap_or(false) + } + + /// Emits the given `cfg` value if `probe_expression` returns true. + pub fn emit_expression_cfg(&self, expr: &str, cfg: &str) { + if self.probe_expression(expr) { + emit(cfg); + } + } + + /// Tests whether the given constant expression can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub const PROBE: () = ((), EXPR).0; + /// ``` + pub fn probe_constant(&self, expr: &str) -> bool { + self.probe(format!("pub const PROBE: () = ((), {}).0;", expr)) + .unwrap_or(false) + } + + /// Emits the given `cfg` value if `probe_constant` returns true. + pub fn emit_constant_cfg(&self, expr: &str, cfg: &str) { + if self.probe_constant(expr) { + emit(cfg); + } + } +} + +fn mangle(s: &str) -> String { + s.chars() + .map(|c| match c { + 'A'...'Z' | 'a'...'z' | '0'...'9' => c, + _ => '_', + }) + .collect() +} + +fn dir_contains_target( + target: &Option, + dir: &PathBuf, + cargo_target_dir: Option, +) -> bool { + target + .as_ref() + .and_then(|target| { + dir.to_str().and_then(|dir| { + let mut cargo_target_dir = cargo_target_dir + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from("target")); + cargo_target_dir.push(target); + + cargo_target_dir + .to_str() + .map(|cargo_target_dir| dir.contains(&cargo_target_dir)) + }) + }) + .unwrap_or(false) +} diff --git a/third_party/cargo/vendor/autocfg-1.0.1/src/tests.rs b/third_party/cargo/vendor/autocfg-1.0.1/src/tests.rs new file mode 100644 index 0000000..4c67462 --- /dev/null +++ b/third_party/cargo/vendor/autocfg-1.0.1/src/tests.rs @@ -0,0 +1,169 @@ +use super::AutoCfg; +use std::env; + +impl AutoCfg { + fn core_std(&self, path: &str) -> String { + let krate = if self.no_std { "core" } else { "std" }; + format!("{}::{}", krate, path) + } + + fn assert_std(&self, probe_result: bool) { + assert_eq!(!self.no_std, probe_result); + } + + fn assert_min(&self, major: usize, minor: usize, probe_result: bool) { + assert_eq!(self.probe_rustc_version(major, minor), probe_result); + } + + fn for_test() -> Result { + match env::var_os("TESTS_TARGET_DIR") { + Some(d) => Self::with_dir(d), + None => Self::with_dir("target"), + } + } +} + +#[test] +fn autocfg_version() { + let ac = AutoCfg::for_test().unwrap(); + println!("version: {:?}", ac.rustc_version); + assert!(ac.probe_rustc_version(1, 0)); +} + +#[test] +fn version_cmp() { + use super::version::Version; + let v123 = Version::new(1, 2, 3); + + assert!(Version::new(1, 0, 0) < v123); + assert!(Version::new(1, 2, 2) < v123); + assert!(Version::new(1, 2, 3) == v123); + assert!(Version::new(1, 2, 4) > v123); + assert!(Version::new(1, 10, 0) > v123); + assert!(Version::new(2, 0, 0) > v123); +} + +#[test] +fn probe_add() { + let ac = AutoCfg::for_test().unwrap(); + let add = ac.core_std("ops::Add"); + let add_rhs = add.clone() + ""; + let add_rhs_output = add.clone() + ""; + let dyn_add_rhs_output = "dyn ".to_string() + &*add_rhs_output; + assert!(ac.probe_path(&add)); + assert!(ac.probe_trait(&add)); + assert!(ac.probe_trait(&add_rhs)); + assert!(ac.probe_trait(&add_rhs_output)); + ac.assert_min(1, 27, ac.probe_type(&dyn_add_rhs_output)); +} + +#[test] +fn probe_as_ref() { + let ac = AutoCfg::for_test().unwrap(); + let as_ref = ac.core_std("convert::AsRef"); + let as_ref_str = as_ref.clone() + ""; + let dyn_as_ref_str = "dyn ".to_string() + &*as_ref_str; + assert!(ac.probe_path(&as_ref)); + assert!(ac.probe_trait(&as_ref_str)); + assert!(ac.probe_type(&as_ref_str)); + ac.assert_min(1, 27, ac.probe_type(&dyn_as_ref_str)); +} + +#[test] +fn probe_i128() { + let ac = AutoCfg::for_test().unwrap(); + let i128_path = ac.core_std("i128"); + ac.assert_min(1, 26, ac.probe_path(&i128_path)); + ac.assert_min(1, 26, ac.probe_type("i128")); +} + +#[test] +fn probe_sum() { + let ac = AutoCfg::for_test().unwrap(); + let sum = ac.core_std("iter::Sum"); + let sum_i32 = sum.clone() + ""; + let dyn_sum_i32 = "dyn ".to_string() + &*sum_i32; + ac.assert_min(1, 12, ac.probe_path(&sum)); + ac.assert_min(1, 12, ac.probe_trait(&sum)); + ac.assert_min(1, 12, ac.probe_trait(&sum_i32)); + ac.assert_min(1, 12, ac.probe_type(&sum_i32)); + ac.assert_min(1, 27, ac.probe_type(&dyn_sum_i32)); +} + +#[test] +fn probe_std() { + let ac = AutoCfg::for_test().unwrap(); + ac.assert_std(ac.probe_sysroot_crate("std")); +} + +#[test] +fn probe_alloc() { + let ac = AutoCfg::for_test().unwrap(); + ac.assert_min(1, 36, ac.probe_sysroot_crate("alloc")); +} + +#[test] +fn probe_bad_sysroot_crate() { + let ac = AutoCfg::for_test().unwrap(); + assert!(!ac.probe_sysroot_crate("doesnt_exist")); +} + +#[test] +fn probe_no_std() { + let ac = AutoCfg::for_test().unwrap(); + assert!(ac.probe_type("i32")); + assert!(ac.probe_type("[i32]")); + ac.assert_std(ac.probe_type("Vec")); +} + +#[test] +fn probe_expression() { + let ac = AutoCfg::for_test().unwrap(); + assert!(ac.probe_expression(r#""test".trim_left()"#)); + ac.assert_min(1, 30, ac.probe_expression(r#""test".trim_start()"#)); + ac.assert_std(ac.probe_expression("[1, 2, 3].to_vec()")); +} + +#[test] +fn probe_constant() { + let ac = AutoCfg::for_test().unwrap(); + assert!(ac.probe_constant("1 + 2 + 3")); + ac.assert_min(1, 33, ac.probe_constant("{ let x = 1 + 2 + 3; x * x }")); + ac.assert_min(1, 39, ac.probe_constant(r#""test".len()"#)); +} + +#[test] +fn dir_does_not_contain_target() { + assert!(!super::dir_contains_target( + &Some("x86_64-unknown-linux-gnu".into()), + &"/project/target/debug/build/project-ea75983148559682/out".into(), + None, + )); +} + +#[test] +fn dir_does_contain_target() { + assert!(super::dir_contains_target( + &Some("x86_64-unknown-linux-gnu".into()), + &"/project/target/x86_64-unknown-linux-gnu/debug/build/project-0147aca016480b9d/out".into(), + None, + )); +} + +#[test] +fn dir_does_not_contain_target_with_custom_target_dir() { + assert!(!super::dir_contains_target( + &Some("x86_64-unknown-linux-gnu".into()), + &"/project/custom/debug/build/project-ea75983148559682/out".into(), + Some("custom".into()), + )); +} + +#[test] +fn dir_does_contain_target_with_custom_target_dir() { + assert!(super::dir_contains_target( + &Some("x86_64-unknown-linux-gnu".into()), + &"/project/custom/x86_64-unknown-linux-gnu/debug/build/project-0147aca016480b9d/out".into(), + Some("custom".into()), + )); +} diff --git a/third_party/cargo/vendor/autocfg-0.1.7/src/version.rs b/third_party/cargo/vendor/autocfg-1.0.1/src/version.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-0.1.7/src/version.rs rename to third_party/cargo/vendor/autocfg-1.0.1/src/version.rs diff --git a/third_party/cargo/vendor/autocfg-1.0.0/tests/rustflags.rs b/third_party/cargo/vendor/autocfg-1.0.1/tests/rustflags.rs similarity index 100% rename from third_party/cargo/vendor/autocfg-1.0.0/tests/rustflags.rs rename to third_party/cargo/vendor/autocfg-1.0.1/tests/rustflags.rs diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/.cargo-checksum.json b/third_party/cargo/vendor/bytemuck-1.2.0/.cargo-checksum.json deleted file mode 100644 index 29bcc92..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"671c72410a736a19fa60d743233baa254c1588a443d9847e25edb3c7e04f2829","LICENSE-ZLIB.md":"84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151","README.md":"4a27f4dcc0e3fbd2b6c4495d310e9179fb7fa4b77a3504821442f769ff4841ba","appveyor.yml":"09c69d96f1d6298a909d514e5a4fcdf0562be65619bdd2cdb966041ade217ef3","bors.toml":"1d8a7a56c5c76925a3daa8c50a40cc82cbfc638f521f864106bd60b1e8a219a2","changelog.md":"cff011496dbe7d4ca419b079e990f568354c0ffc230101486a08261d57c2da8a","pedantic.bat":"afd79f32caf7dc86e0390838992030decc5024c1348c86eb1c519c9c832bfe5e","rustfmt.toml":"1717bca34bc413693c82b6c50d633be8023545fa9a387b2da817ae848e2f1fc1","scripts/travis.sh":"a57fcf5ece149dd6da26481ebb429f359ccebd733a73de2e87f451371302142b","src/allocation.rs":"5bee031d7a2e4e7201543b0a4181c4f95e461049b045d3a3ab489819677847d9","src/contiguous.rs":"288aa77eca807f47d28c4372f6eb3fd87d885dcaf886fb725c10fdbaf1fd27d0","src/lib.rs":"32baa9a75add0916856e25fa37b3f5082c319d20f523e09d747b0b46333f3e0a","src/offset_of.rs":"aa89eb88ab3acd5694936e9bc922de5d0923e991afe732803946e4b66d7f2ef2","src/pod.rs":"b64399dac0d0dcc6179b4da48c02a15dee881afe858d27aed58253775016f4da","src/transparent.rs":"7d72eaa199c8b8656df324e7a846eb5589cb848080ecb4a75cbbef3b284ee46b","src/zeroable.rs":"c1ab8a5b9af7094fa710338529ee31588e616e2f954db1df0c98b15bbd1a18f6","tests/cast_slice_tests.rs":"de4a5879b0ef74df96ffe04412d7da49364725812e8ba1770e43867d58d8952c","tests/doc_tests.rs":"0008789fc7281f581c8c91eac13ea4683f82cdeadadc4119c7b21b38f7d41577","tests/std_tests.rs":"69661f26dc385c38d6c2bd37a62ba476e81ef88b4ed6565f3a47dd173133365c"},"package":"37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431"} \ No newline at end of file diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/BUILD.bazel b/third_party/cargo/vendor/bytemuck-1.2.0/BUILD.bazel deleted file mode 100644 index c7eed05..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/BUILD.bazel +++ /dev/null @@ -1,59 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # Zlib from expression "Zlib" -]) - -# Generated Targets - -rust_library( - name = "bytemuck", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2018", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.2.0", - # buildifier: leave-alone - deps = [ - ], -) - -# Unsupported target "cast_slice_tests" with type "test" omitted - -# Unsupported target "doc_tests" with type "test" omitted - -# Unsupported target "std_tests" with type "test" omitted diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/Cargo.toml b/third_party/cargo/vendor/bytemuck-1.2.0/Cargo.toml deleted file mode 100644 index e06c9c0..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "bytemuck" -version = "1.2.0" -authors = ["Lokathor "] -description = "A crate for mucking around with piles of bytes." -readme = "README.md" -keywords = ["transmute", "bytes", "casting"] -categories = ["encoding", "no-std"] -license = "Zlib" -repository = "https://github.com/Lokathor/bytemuck" -[package.metadata.docs.rs] -all-features = true - -[features] -extern_crate_alloc = [] -[badges.appveyor] -repository = "Lokathor/bytemuck" - -[badges.travis-ci] -repository = "Lokathor/bytemuck" diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/README.md b/third_party/cargo/vendor/bytemuck-1.2.0/README.md deleted file mode 100644 index 94080c5..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/README.md +++ /dev/null @@ -1,26 +0,0 @@ -[![License:Zlib](https://img.shields.io/badge/License-Zlib-brightgreen.svg)](https://opensource.org/licenses/Zlib) -![Minimum Rust Version](https://img.shields.io/badge/Min%20Rust-1.34-green.svg) -[![travis.ci](https://travis-ci.org/Lokathor/bytemuck.svg?branch=master)](https://travis-ci.org/Lokathor/bytemuck) -[![AppVeyor](https://ci.appveyor.com/api/projects/status/hgr4if0snmkmqj88/branch/master?svg=true)](https://ci.appveyor.com/project/Lokathor/bytemuck/branch/master) -[![crates.io](https://img.shields.io/crates/v/bytemuck.svg)](https://crates.io/crates/bytemuck) -[![docs.rs](https://docs.rs/bytemuck/badge.svg)](https://docs.rs/bytemuck/) - -# bytemuck - -A crate for mucking around with piles of bytes. - -## Extensions - -There is experimental support for the `Zeroable` trait being derived through a -proc-macro. I'm not the author of that crate, please file bugs with that crate -in the other repo. - -* https://github.com/rodrimati1992/zeroable_crates - -## Stability - -The goal is to stay at 1.y.z until _at least_ the next edition of Rust. - -I consider any increase of the Minimum Rust Version to be a semver breaking change, -so `rustc-1.34` will continue to be supported for at least the rest of the -`bytemuck-1.y.z` series of the crate. diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/appveyor.yml b/third_party/cargo/vendor/bytemuck-1.2.0/appveyor.yml deleted file mode 100644 index d6c4f5e..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/appveyor.yml +++ /dev/null @@ -1,45 +0,0 @@ - -os: Visual Studio 2015 - -branches: - only: - - staging - - trying - - master - - dev - -matrix: - fast_finish: true - -environment: - matrix: - # Stable - - channel: 1.34.0 - target: i686-pc-windows-msvc - - channel: 1.34.0 - target: i686-pc-windows-gnu - - channel: 1.34.0 - target: x86_64-pc-windows-msvc - - channel: 1.34.0 - target: x86_64-pc-windows-gnu - # Beta and Nightly are checked by TravisCI since builds there run in - # parallel. - -install: - - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init -y --default-toolchain %channel% --default-host %target% - - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - - rustup component add rustfmt - - rustup component add clippy - - rustc -vV - - cargo -vV - -# On advice of retep we skip the "build" script phase -build: false - -test_script: - - cargo fmt -- --check - - cargo clippy - - cargo test --no-default-features - - cargo test - #- cargo test --all-features diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/bors.toml b/third_party/cargo/vendor/bytemuck-1.2.0/bors.toml deleted file mode 100644 index 359f894..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/bors.toml +++ /dev/null @@ -1 +0,0 @@ -status = ["continuous-integration/travis-ci/push"] diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/changelog.md b/third_party/cargo/vendor/bytemuck-1.2.0/changelog.md deleted file mode 100644 index 9c2e2a9..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/changelog.md +++ /dev/null @@ -1,25 +0,0 @@ -# `bytemuck` changelog - -## 1.2.0 - -* [thomcc](https://github.com/thomcc) added many things: - * A fully sound `offset_of!` macro [#10](https://github.com/Lokathor/bytemuck/pull/10) - * A `Contiguous` trait for when you've got enums with declared values - all in a row [#12](https://github.com/Lokathor/bytemuck/pull/12) - * A `TransparentWrapper` marker trait for when you want to more clearly - enable adding and removing a wrapper struct to its inner value - [#15](https://github.com/Lokathor/bytemuck/pull/15) - * Now MIRI is run on CI in every sigle push! - [#16](https://github.com/Lokathor/bytemuck/pull/16) - -## 1.1.0 - -* [SimonSapin](https://github.com/SimonSapin) added `from_bytes`, - `from_bytes_mut`, `try_from_bytes`, and `try_from_bytes_mut` ([PR - Link](https://github.com/Lokathor/bytemuck/pull/8)) - -## 1.0.1 - -* Changed to the [zlib](https://opensource.org/licenses/Zlib) license. -* Added much more proper documentation. -* Reduced the minimum Rust version to 1.34 diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/pedantic.bat b/third_party/cargo/vendor/bytemuck-1.2.0/pedantic.bat deleted file mode 100644 index d6323bf..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/pedantic.bat +++ /dev/null @@ -1 +0,0 @@ -cargo clippy -- -W clippy::pedantic diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/rustfmt.toml b/third_party/cargo/vendor/bytemuck-1.2.0/rustfmt.toml deleted file mode 100644 index 50860b8..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/rustfmt.toml +++ /dev/null @@ -1,8 +0,0 @@ -error_on_line_overflow = false -merge_imports = true -reorder_imports = true -use_try_shorthand = true -tab_spaces = 2 -max_width = 80 -color = "Never" -use_small_heuristics = "Max" diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/scripts/travis.sh b/third_party/cargo/vendor/bytemuck-1.2.0/scripts/travis.sh deleted file mode 100755 index 31201ce..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/scripts/travis.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -set -e - -if [[ "$RUN_MIRI" != "" ]]; then - - cargo clean - - # Install and run the latest version of nightly where miri built successfully. - # Taken from: https://github.com/rust-lang/miri#running-miri-on-ci - - MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) - echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" - rustup set profile minimal - rustup default "$MIRI_NIGHTLY" - - rustup component add miri - cargo miri setup - - cargo miri test --verbose - cargo miri test --verbose --no-default-features - cargo miri test --verbose --all-features - -else - - rustup component add clippy - cargo clippy - - if [[ "$TARGET" != "" ]]; then rustup target install $TARGET; fi - - if [[ "$TARGET" == "wasm32-"* && "$TARGET" != "wasm32-wasi" ]]; then - cargo-web --version || cargo install cargo-web - cargo web test --no-default-features $FLAGS --target=$TARGET - cargo web test $FLAGS --target=$TARGET - #cargo web test --all-features $FLAGS --target=$TARGET - - elif [[ "$TARGET" == *"-linux-android"* ]]; then - export PATH=/usr/local/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH - pushd linux-android - cargo build --no-default-features --target=$TARGET $FLAGS - cargo build --target=$TARGET $FLAGS - #cargo build --all-features --target=$TARGET $FLAGS - # Don't test, can't run android emulators successfully on travis currently - popd - - elif [[ "$TARGET" == *"-apple-ios" || "$TARGET" == "wasm32-wasi" ]]; then - cargo build --no-default-features --target=$TARGET $FLAGS - cargo build --target=$TARGET $FLAGS - #cargo build --all-features --target=$TARGET $FLAGS - # Don't test - # iOS simulator setup/teardown is complicated - # cargo-web doesn't support wasm32-wasi yet, nor can wasm-pack test specify a target - - elif [[ "$TARGET" == *"-unknown-linux-gnueabihf" ]]; then - #sudo apt-get update - #sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf - pushd generic-cross - cargo build --no-default-features --target=$TARGET $FLAGS - cargo build --target=$TARGET $FLAGS - #cargo build --all-features --target=$TARGET $FLAGS - # Don't test - popd - - elif [[ "$TARGET" != "" ]]; then - pushd generic-cross - cargo test --no-default-features --target=$TARGET $FLAGS - cargo test --target=$TARGET $FLAGS - #cargo test --all-features --target=$TARGET $FLAGS - popd - - else - # Push nothing, target host CPU architecture - cargo test --no-default-features $FLAGS - cargo test $FLAGS - fi - -fi diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/allocation.rs b/third_party/cargo/vendor/bytemuck-1.2.0/src/allocation.rs deleted file mode 100644 index 0676f3f..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/src/allocation.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! Stuff to boost things in the `alloc` crate. -//! -//! * You must enable the `extern_crate_alloc` feature of `bytemuck` or you will -//! not be able to use this module! - -use super::*; -use alloc::{ - alloc::{alloc_zeroed, Layout}, - boxed::Box, - vec::Vec, -}; - -/// As [`try_cast_box`](try_cast_box), but unwraps for you. -#[inline] -pub fn cast_box(input: Box) -> Box { - try_cast_box(input).map_err(|(e, _v)| e).unwrap() -} - -/// Attempts to cast the content type of a [`Box`](alloc::boxed::Box). -/// -/// On failure you get back an error along with the starting `Box`. -/// -/// ## Failure -/// -/// * The start and end content type of the `Box` must have the exact same -/// alignment. -/// * The start and end size of the `Box` must have the exact same size. -#[inline] -pub fn try_cast_box( - input: Box, -) -> Result, (PodCastError, Box)> { - if align_of::() != align_of::() { - Err((PodCastError::AlignmentMismatch, input)) - } else if size_of::() != size_of::() { - Err((PodCastError::SizeMismatch, input)) - } else { - // Note(Lokathor): This is much simpler than with the Vec casting! - let ptr: *mut B = Box::into_raw(input) as *mut B; - Ok(unsafe { Box::from_raw(ptr) }) - } -} - -/// Allocates a `Box` with all of the contents being zeroed out. -/// -/// This uses the global allocator to create a zeroed allocation and _then_ -/// turns it into a Box. In other words, it's 100% assured that the zeroed data -/// won't be put temporarily on the stack. You can make a box of any size -/// without fear of a stack overflow. -/// -/// ## Failure -/// -/// This fails if the allocation fails. -#[inline] -pub fn try_zeroed_box() -> Result, ()> { - if size_of::() == 0 { - return Ok(Box::new(T::zeroed())); - } - let layout = - Layout::from_size_align(size_of::(), align_of::()).unwrap(); - let ptr = unsafe { alloc_zeroed(layout) }; - if ptr.is_null() { - // we don't know what the error is because `alloc_zeroed` is a dumb API - Err(()) - } else { - Ok(unsafe { Box::::from_raw(ptr as *mut T) }) - } -} - -/// As [`try_zeroed_box`], but unwraps for you. -#[inline] -pub fn zeroed_box() -> Box { - try_zeroed_box().unwrap() -} - -/// As [`try_cast_vec`](try_cast_vec), but unwraps for you. -#[inline] -pub fn cast_vec(input: Vec) -> Vec { - try_cast_vec(input).map_err(|(e, _v)| e).unwrap() -} - -/// Attempts to cast the content type of a [`Vec`](alloc::vec::Vec). -/// -/// On failure you get back an error along with the starting `Vec`. -/// -/// ## Failure -/// -/// * The start and end content type of the `Vec` must have the exact same -/// alignment. -/// * The start and end size of the `Vec` must have the exact same size. -/// * In the future this second restriction might be lessened by having the -/// capacity and length get adjusted during transmutation, but for now it's -/// absolute. -#[inline] -pub fn try_cast_vec( - input: Vec, -) -> Result, (PodCastError, Vec)> { - if align_of::() != align_of::() { - Err((PodCastError::AlignmentMismatch, input)) - } else if size_of::() != size_of::() { - // Note(Lokathor): Under some conditions it would be possible to cast - // between Vec content types of the same alignment but different sizes by - // changing the capacity and len values in the output Vec. However, we will - // not attempt that for now. - Err((PodCastError::SizeMismatch, input)) - } else { - // Note(Lokathor): First we record the length and capacity, which don't have - // any secret provenance metadata. - let length: usize = input.len(); - let capacity: usize = input.capacity(); - // Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with - // ManuallyDrop, because if we used `core::mem::forget` after taking the - // pointer then that would invalidate our pointer. In nightly there's a - // "into raw parts" method, which we can switch this too eventually. - let mut manual_drop_vec = ManuallyDrop::new(input); - let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr(); - let ptr: *mut B = vec_ptr as *mut B; - Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) }) - } -} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/lib.rs b/third_party/cargo/vendor/bytemuck-1.2.0/src/lib.rs deleted file mode 100644 index a90199d..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/src/lib.rs +++ /dev/null @@ -1,433 +0,0 @@ -#![no_std] -#![warn(missing_docs)] - -//! This crate gives small utilities for casting between plain data types. -//! -//! ## Basics -//! -//! Data comes in five basic forms in Rust, so we have five basic casting -//! functions: -//! -//! * `T` uses [`cast`] -//! * `&T` uses [`cast_ref`] -//! * `&mut T` uses [`cast_mut`] -//! * `&[T]` uses [`cast_slice`] -//! * `&mut [T]` uses [`cast_slice_mut`] -//! -//! Some casts will never fail (eg: `cast::` always works), other -//! casts might fail (eg: `cast_ref::<[u8; 4], u32>` will fail if the reference -//! isn't already aligned to 4). Each casting function has a "try" version which -//! will return a `Result`, and the "normal" version which will simply panic on -//! invalid input. -//! -//! ## Using Your Own Types -//! -//! All the functions here are guarded by the [`Pod`] trait, which is a -//! sub-trait of the [`Zeroable`] trait. -//! -//! If you're very sure that your type is eligible, you can implement those -//! traits for your type and then they'll have full casting support. However, -//! these traits are `unsafe`, and you should carefully read the requirements -//! before adding the them to your own types. -//! -//! ## Features -//! -//! * This crate is core only by default, but if you're using Rust 1.36 or later -//! you can enable the `extern_crate_alloc` cargo feature for some additional -//! methods related to `Box` and `Vec`. Note that the `docs.rs` documentation -//! is always built with `extern_crate_alloc` cargo feature enabled. - -#[cfg(target_arch = "x86")] -use core::arch::x86; -#[cfg(target_arch = "x86_64")] -use core::arch::x86_64; -// -use core::{marker::*, mem::*, num::*, ptr::*}; - -// Used from macros to ensure we aren't using some locally defined name and -// actually are referencing libcore. This also would allow pre-2018 edition -// crates to use our macros, but I'm not sure how important that is. -#[doc(hidden)] -pub use ::core as __core; - -macro_rules! impl_unsafe_marker_for_array { - ( $marker:ident , $( $n:expr ),* ) => { - $(unsafe impl $marker for [T; $n] where T: $marker {})* - } -} - -#[cfg(feature = "extern_crate_alloc")] -extern crate alloc; -#[cfg(feature = "extern_crate_alloc")] -pub mod allocation; -#[cfg(feature = "extern_crate_alloc")] -pub use allocation::*; - -mod zeroable; -pub use zeroable::*; - -mod pod; -pub use pod::*; - -mod contiguous; -pub use contiguous::*; - -mod offset_of; -pub use offset_of::*; - -mod transparent; -pub use transparent::*; - -/* - -Note(Lokathor): We've switched all of the `unwrap` to `match` because there is -apparently a bug: https://github.com/rust-lang/rust/issues/68667 -and it doesn't seem to show up in simple godbolt examples but has been reported -as having an impact when there's a cast mixed in with other more complicated -code around it. Rustc/LLVM ends up missing that the `Err` can't ever happen for -particular type combinations, and then it doesn't fully eliminated the panic -possibility code branch. - -*/ - -/// Immediately panics. -#[cold] -#[inline(never)] -fn something_went_wrong(src: &str, err: PodCastError) -> ! { - // Note(Lokathor): Keeping the panic here makes the panic _formatting_ go - // here too, which helps assembly readability and also helps keep down - // the inline pressure. - panic!("{src}>{err:?}", src = src, err = err) -} - -/// Re-interprets `&T` as `&[u8]`. -/// -/// Any ZST becomes an empty slice, and in that case the pointer value of that -/// empty slice might not match the pointer value of the input reference. -#[inline] -pub fn bytes_of(t: &T) -> &[u8] { - match try_cast_slice::(core::slice::from_ref(t)) { - Ok(s) => s, - Err(_) => unreachable!(), - } -} - -/// Re-interprets `&mut T` as `&mut [u8]`. -/// -/// Any ZST becomes an empty slice, and in that case the pointer value of that -/// empty slice might not match the pointer value of the input reference. -#[inline] -pub fn bytes_of_mut(t: &mut T) -> &mut [u8] { - match try_cast_slice_mut::(core::slice::from_mut(t)) { - Ok(s) => s, - Err(_) => unreachable!(), - } -} - -/// Re-interprets `&[u8]` as `&T`. -/// -/// ## Panics -/// -/// This is [`try_from_bytes`] but will panic on error. -#[inline] -pub fn from_bytes(s: &[u8]) -> &T { - match try_from_bytes(s) { - Ok(t) => t, - Err(e) => something_went_wrong("from_bytes", e), - } -} - -/// Re-interprets `&mut [u8]` as `&mut T`. -/// -/// ## Panics -/// -/// This is [`try_from_bytes_mut`] but will panic on error. -#[inline] -pub fn from_bytes_mut(s: &mut [u8]) -> &mut T { - match try_from_bytes_mut(s) { - Ok(t) => t, - Err(e) => something_went_wrong("from_bytes_mut", e), - } -} - -/// Re-interprets `&[u8]` as `&T`. -/// -/// ## Failure -/// -/// * If the slice isn't aligned for the new type -/// * If the slice's length isn’t exactly the size of the new type -#[inline] -pub fn try_from_bytes(s: &[u8]) -> Result<&T, PodCastError> { - if s.len() != size_of::() { - Err(PodCastError::SizeMismatch) - } else if (s.as_ptr() as usize) % align_of::() != 0 { - Err(PodCastError::AlignmentMismatch) - } else { - Ok(unsafe { &*(s.as_ptr() as *const T) }) - } -} - -/// Re-interprets `&mut [u8]` as `&mut T`. -/// -/// ## Failure -/// -/// * If the slice isn't aligned for the new type -/// * If the slice's length isn’t exactly the size of the new type -#[inline] -pub fn try_from_bytes_mut( - s: &mut [u8], -) -> Result<&mut T, PodCastError> { - if s.len() != size_of::() { - Err(PodCastError::SizeMismatch) - } else if (s.as_ptr() as usize) % align_of::() != 0 { - Err(PodCastError::AlignmentMismatch) - } else { - Ok(unsafe { &mut *(s.as_mut_ptr() as *mut T) }) - } -} - -/// The things that can go wrong when casting between [`Pod`] data forms. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PodCastError { - /// You tried to cast a slice to an element type with a higher alignment - /// requirement but the slice wasn't aligned. - TargetAlignmentGreaterAndInputNotAligned, - /// If the element size changes then the output slice changes length - /// accordingly. If the output slice wouldn't be a whole number of elements - /// then the conversion fails. - OutputSliceWouldHaveSlop, - /// When casting a slice you can't convert between ZST elements and non-ZST - /// elements. When casting an individual `T`, `&T`, or `&mut T` value the - /// source size and destination size must be an exact match. - SizeMismatch, - /// For this type of cast the alignments must be exactly the same and they - /// were not so now you're sad. - AlignmentMismatch, -} - -/// Cast `T` into `U` -/// -/// ## Panics -/// -/// This is [`try_cast`] but will panic on error. -#[inline] -pub fn cast(a: A) -> B { - if size_of::() == size_of::() { - // Plz mr compiler, just notice that we can't ever hit Err in this case. - match try_cast(a) { - Ok(b) => b, - Err(_) => unreachable!(), - } - } else { - match try_cast(a) { - Ok(b) => b, - Err(e) => something_went_wrong("cast", e), - } - } -} - -/// Cast `&mut T` into `&mut U`. -/// -/// ## Panics -/// -/// This is [`try_cast_mut`] but will panic on error. -#[inline] -pub fn cast_mut(a: &mut A) -> &mut B { - if size_of::() == size_of::() && align_of::() >= align_of::() { - // Plz mr compiler, just notice that we can't ever hit Err in this case. - match try_cast_mut(a) { - Ok(b) => b, - Err(_) => unreachable!(), - } - } else { - match try_cast_mut(a) { - Ok(b) => b, - Err(e) => something_went_wrong("cast_mut", e), - } - } -} - -/// Cast `&T` into `&U`. -/// -/// ## Panics -/// -/// This is [`try_cast_ref`] but will panic on error. -#[inline] -pub fn cast_ref(a: &A) -> &B { - if size_of::() == size_of::() && align_of::() >= align_of::() { - // Plz mr compiler, just notice that we can't ever hit Err in this case. - match try_cast_ref(a) { - Ok(b) => b, - Err(_) => unreachable!(), - } - } else { - match try_cast_ref(a) { - Ok(b) => b, - Err(e) => something_went_wrong("cast_ref", e), - } - } -} - -/// Cast `&[T]` into `&[U]`. -/// -/// ## Panics -/// -/// This is [`try_cast_slice`] but will panic on error. -#[inline] -pub fn cast_slice(a: &[A]) -> &[B] { - match try_cast_slice(a) { - Ok(b) => b, - Err(e) => something_went_wrong("cast_slice", e), - } -} - -/// Cast `&mut [T]` into `&mut [U]`. -/// -/// ## Panics -/// -/// This is [`try_cast_slice_mut`] but will panic on error. -#[inline] -pub fn cast_slice_mut(a: &mut [A]) -> &mut [B] { - match try_cast_slice_mut(a) { - Ok(b) => b, - Err(e) => something_went_wrong("cast_slice_mut", e), - } -} - -/// As `align_to`, but safe because of the [`Pod`] bound. -#[inline] -pub fn pod_align_to(vals: &[T]) -> (&[T], &[U], &[T]) { - unsafe { vals.align_to::() } -} - -/// As `align_to_mut`, but safe because of the [`Pod`] bound. -#[inline] -pub fn pod_align_to_mut( - vals: &mut [T], -) -> (&mut [T], &mut [U], &mut [T]) { - unsafe { vals.align_to_mut::() } -} - -/// Try to cast `T` into `U`. -/// -/// ## Failure -/// -/// * If the types don't have the same size this fails. -#[inline] -pub fn try_cast(a: A) -> Result { - if size_of::() == size_of::() { - let mut b = B::zeroed(); - // Note(Lokathor): We copy in terms of `u8` because that allows us to bypass - // any potential alignment difficulties. - let ap = &a as *const A as *const u8; - let bp = &mut b as *mut B as *mut u8; - unsafe { ap.copy_to_nonoverlapping(bp, size_of::()) }; - Ok(b) - } else { - Err(PodCastError::SizeMismatch) - } -} - -/// Try to convert a `&T` into `&U`. -/// -/// ## Failure -/// -/// * If the reference isn't aligned in the new type -/// * If the source type and target type aren't the same size. -#[inline] -pub fn try_cast_ref(a: &A) -> Result<&B, PodCastError> { - // Note(Lokathor): everything with `align_of` and `size_of` will optimize away - // after monomorphization. - if align_of::() > align_of::() - && (a as *const A as usize) % align_of::() != 0 - { - Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) - } else if size_of::() == size_of::() { - Ok(unsafe { &*(a as *const A as *const B) }) - } else { - Err(PodCastError::SizeMismatch) - } -} - -/// Try to convert a `&mut T` into `&mut U`. -/// -/// As [`try_cast_ref`], but `mut`. -#[inline] -pub fn try_cast_mut(a: &mut A) -> Result<&mut B, PodCastError> { - // Note(Lokathor): everything with `align_of` and `size_of` will optimize away - // after monomorphization. - if align_of::() > align_of::() - && (a as *mut A as usize) % align_of::() != 0 - { - Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) - } else if size_of::() == size_of::() { - Ok(unsafe { &mut *(a as *mut A as *mut B) }) - } else { - Err(PodCastError::SizeMismatch) - } -} - -/// Try to convert `&[T]` into `&[U]` (possibly with a change in length). -/// -/// * `input.as_ptr() as usize == output.as_ptr() as usize` -/// * `input.len() * size_of::() == output.len() * size_of::()` -/// -/// ## Failure -/// -/// * If the target type has a greater alignment requirement and the input slice -/// isn't aligned. -/// * If the target element type is a different size from the current element -/// type, and the output slice wouldn't be a whole number of elements when -/// accounting for the size change (eg: 3 `u16` values is 1.5 `u32` values, so -/// that's a failure). -/// * Similarly, you can't convert between a -/// [ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts) -/// and a non-ZST. -#[inline] -pub fn try_cast_slice(a: &[A]) -> Result<&[B], PodCastError> { - // Note(Lokathor): everything with `align_of` and `size_of` will optimize away - // after monomorphization. - if align_of::() > align_of::() - && (a.as_ptr() as usize) % align_of::() != 0 - { - Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) - } else if size_of::() == size_of::() { - Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, a.len()) }) - } else if size_of::() == 0 || size_of::() == 0 { - Err(PodCastError::SizeMismatch) - } else if core::mem::size_of_val(a) % size_of::() == 0 { - let new_len = core::mem::size_of_val(a) / size_of::(); - Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) }) - } else { - Err(PodCastError::OutputSliceWouldHaveSlop) - } -} - -/// Try to convert `&mut [T]` into `&mut [U]` (possibly with a change in length). -/// -/// As [`try_cast_slice`], but `&mut`. -#[inline] -pub fn try_cast_slice_mut( - a: &mut [A], -) -> Result<&mut [B], PodCastError> { - // Note(Lokathor): everything with `align_of` and `size_of` will optimize away - // after monomorphization. - if align_of::() > align_of::() - && (a.as_mut_ptr() as usize) % align_of::() != 0 - { - Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) - } else if size_of::() == size_of::() { - Ok(unsafe { - core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len()) - }) - } else if size_of::() == 0 || size_of::() == 0 { - Err(PodCastError::SizeMismatch) - } else if core::mem::size_of_val(a) % size_of::() == 0 { - let new_len = core::mem::size_of_val(a) / size_of::(); - Ok(unsafe { - core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) - }) - } else { - Err(PodCastError::OutputSliceWouldHaveSlop) - } -} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/offset_of.rs b/third_party/cargo/vendor/bytemuck-1.2.0/src/offset_of.rs deleted file mode 100644 index fa85727..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/src/offset_of.rs +++ /dev/null @@ -1,103 +0,0 @@ -#![forbid(unsafe_code)] - -/// Find the offset in bytes of the given `$field` of `$Type`, using `$instance` -/// as an already-initialized value to work with. -/// -/// This is similar to the macro from `memoffset`, however it's fully well -/// defined even in current versions of Rust (and uses no unsafe code). -/// -/// It does by using the `$instance` argument to have an already-initialized -/// instance of `$Type` rather than trying to find a way access the fields of an -/// uninitialized one without hitting soundness problems. The value passed to -/// the macro is referenced but not moved. -/// -/// This means the API is more limited, but it's also sound even in rather -/// extreme cases, like some of the examples. -/// -/// ## Caveats -/// -/// 1. The offset is in bytes, and so you will likely have to cast your base -/// pointers to `*const u8`/`*mut u8` before getting field addresses. -/// -/// 2. The offset values of repr(Rust) types are not stable, and may change -/// wildly between releases of the compiler. Use repr(C) if you can. -/// -/// 3. The value of the `$instance` parameter has no bearing on the output of -/// this macro. It is just used to avoid soundness problems. The only -/// requirement is that it be initialized. In particular, the value returned -/// is not a field pointer, or anything like that. -/// -/// ## Examples -/// -/// ### Use with zeroable types -/// A common requirement in GPU apis is to specify the layout of vertices. These -/// will generally be [`Zeroable`] (if not [`Pod`]), and are a good fit for -/// `offset_of!`. -/// ``` -/// # use bytemuck::{Zeroable, offset_of}; -/// #[repr(C)] -/// struct Vertex { -/// pos: [f32; 2], -/// uv: [u16; 2], -/// color: [u8; 4], -/// } -/// unsafe impl Zeroable for Vertex {} -/// -/// let pos = offset_of!(Zeroable::zeroed(), Vertex, pos); -/// let uv = offset_of!(Zeroable::zeroed(), Vertex, uv); -/// let color = offset_of!(Zeroable::zeroed(), Vertex, color); -/// -/// assert_eq!(pos, 0); -/// assert_eq!(uv, 8); -/// assert_eq!(color, 12); -/// ``` -/// -/// ### Use with other types -/// -/// More esoteric uses are possible too, including with types generally not safe -/// to otherwise use with bytemuck. `Strings`, `Vec`s, etc. -/// -/// ``` -/// #[derive(Default)] -/// struct Foo { -/// a: u8, -/// b: &'static str, -/// c: i32, -/// } -/// -/// let a_offset = bytemuck::offset_of!(Default::default(), Foo, a); -/// let b_offset = bytemuck::offset_of!(Default::default(), Foo, b); -/// let c_offset = bytemuck::offset_of!(Default::default(), Foo, c); -/// -/// assert_ne!(a_offset, b_offset); -/// assert_ne!(b_offset, c_offset); -/// // We can't check against hardcoded values for a repr(Rust) type, -/// // but prove to ourself this way. -/// -/// let foo = Foo::default(); -/// // Note: offsets are in bytes. -/// let as_bytes = &foo as *const _ as *const u8; -/// -/// // we're using wrapping_offset here becasue it's not worth -/// // the unsafe block, but it would be valid to use `add` instead, -/// // as it cannot overflow. -/// assert_eq!(&foo.a as *const _ as usize, as_bytes.wrapping_add(a_offset) as usize); -/// assert_eq!(&foo.b as *const _ as usize, as_bytes.wrapping_add(b_offset) as usize); -/// assert_eq!(&foo.c as *const _ as usize, as_bytes.wrapping_add(c_offset) as usize); -/// ``` -#[macro_export] -macro_rules! offset_of { - ($instance:expr, $Type:path, $field:tt) => {{ - // This helps us guard against field access going through a Deref impl. - #[allow(clippy::unneeded_field_pattern)] - let $Type { $field: _, .. }; - let reference: &$Type = &$instance; - let address = reference as *const _ as usize; - let field_pointer = &reference.$field as *const _ as usize; - // These asserts/unwraps are compiled away at release, and defend against - // the case where somehow a deref impl is still invoked. - let result = field_pointer.checked_sub(address).unwrap(); - assert!(result <= $crate::__core::mem::size_of::<$Type>()); - result - }}; -} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/transparent.rs b/third_party/cargo/vendor/bytemuck-1.2.0/src/transparent.rs deleted file mode 100644 index b77a870..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/src/transparent.rs +++ /dev/null @@ -1,133 +0,0 @@ -use super::*; - -/// A trait which indicates that a type is a `repr(transparent)` wrapper around -/// the `Wrapped` value. -/// -/// This allows safely creating references to `T` from those to the `Wrapped` -/// type, using the `wrap_ref` and `wrap_mut` functions. -/// -/// # Safety -/// -/// The safety contract of `TransparentWrapper` is relatively simple: -/// -/// For a given `Wrapper` which implements `TransparentWrapper`: -/// -/// 1. Wrapper must be a `#[repr(transparent)]` wrapper around `Wrapped`. This -/// either means that it must be a `#[repr(transparent)]` struct which -/// contains a either a field of type `Wrapped` (or a field of some other -/// transparent wrapper for `Wrapped`) as the only non-ZST field. -/// -/// 2. Any fields *other* than the `Wrapped` field must be trivially -/// constructable ZSTs, for example `PhantomData`, `PhantomPinned`, etc. -/// -/// 3. The `Wrapper` may not impose additional alignment requirements over -/// `Wrapped`. -/// - Note: this is currently guaranteed by repr(transparent), but there -/// have been discussions of lifting it, so it's stated here explictly. -/// -/// 4. The `wrap_ref` and `wrap_mut` functions on `TransparentWrapper` may not -/// be overridden. -/// -/// ## Caveats -/// -/// If the wrapper imposes additional constraints upon the wrapped type which -/// are required for safety, it's responsible for ensuring those still hold -- -/// this generally requires preventing access to instances of the wrapped type, -/// as implementing `TransparentWrapper for T` means anybody can call -/// `T::cast_ref(any_instance_of_u)`. -/// -/// For example, it would be invalid to implement TransparentWrapper for `str` -/// to implement `TransparentWrapper` around `[u8]` because of this. -/// -/// # Examples -/// -/// ## Basic -/// -/// ``` -/// use bytemuck::TransparentWrapper; -/// # #[derive(Default)] -/// # struct SomeStruct(u32); -/// -/// #[repr(transparent)] -/// struct MyWrapper(SomeStruct); -/// -/// unsafe impl TransparentWrapper for MyWrapper {} -/// -/// // interpret a reference to &SomeStruct as a &MyWrapper -/// let thing = SomeStruct::default(); -/// let wrapped_ref: &MyWrapper = MyWrapper::wrap_ref(&thing); -/// -/// // Works with &mut too. -/// let mut mut_thing = SomeStruct::default(); -/// let wrapped_mut: &mut MyWrapper = MyWrapper::wrap_mut(&mut mut_thing); -/// -/// # let _ = (wrapped_ref, wrapped_mut); // silence warnings -/// ``` -/// -/// ## Use with dynamically sized types -/// -/// ``` -/// use bytemuck::TransparentWrapper; -/// -/// #[repr(transparent)] -/// struct Slice([T]); -/// -/// unsafe impl TransparentWrapper<[T]> for Slice {} -/// -/// let s = Slice::wrap_ref(&[1u32, 2, 3]); -/// assert_eq!(&s.0, &[1, 2, 3]); -/// -/// let mut buf = [1, 2, 3u8]; -/// let sm = Slice::wrap_mut(&mut buf); -/// ``` -pub unsafe trait TransparentWrapper { - /// Convert a reference to a wrapped type into a reference to the wrapper. - /// - /// This is a trait method so that you can write `MyType::wrap_ref(...)` in - /// your code. It is part of the safety contract for this trait that if you - /// implement `TransparentWrapper<_>` for your type you **must not** override - /// this method. - #[inline] - fn wrap_ref(s: &Wrapped) -> &Self { - unsafe { - assert!(size_of::<*const Wrapped>() == size_of::<*const Self>()); - // Using a pointer cast doesn't work here because rustc can't tell that the - // vtables match (if we lifted the ?Sized restriction, this would go away), - // and transmute doesn't work for the usual reasons it doesn't work inside - // generic functions. - // - // SAFETY: The unsafe contract requires that these have identical - // representations. Using this transmute_copy instead of transmute here is - // annoying, but is required as `Self` and `Wrapped` have unspecified - // sizes still. - let wrapped_ptr = s as *const Wrapped; - let wrapper_ptr: *const Self = transmute_copy(&wrapped_ptr); - &*wrapper_ptr - } - } - - /// Convert a mut reference to a wrapped type into a mut reference to the - /// wrapper. - /// - /// This is a trait method so that you can write `MyType::wrap_mut(...)` in - /// your code. It is part of the safety contract for this trait that if you implement - /// `TransparentWrapper<_>` for your type you **must not** override this method. - #[inline] - fn wrap_mut(s: &mut Wrapped) -> &mut Self { - unsafe { - assert!(size_of::<*mut Wrapped>() == size_of::<*mut Self>()); - // Using a pointer cast doesn't work here because rustc can't tell that the - // vtables match (if we lifted the ?Sized restriction, this would go away), - // and transmute doesn't work for the usual reasons it doesn't work inside - // generic functions. - // - // SAFETY: The unsafe contract requires that these have identical - // representations. Using this transmute_copy instead of transmute here is - // annoying, but is required as `Self` and `Wrapped` have unspecified - // sizes still. - let wrapped_ptr = s as *mut Wrapped; - let wrapper_ptr: *mut Self = transmute_copy(&wrapped_ptr); - &mut *wrapper_ptr - } - } -} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/tests/cast_slice_tests.rs b/third_party/cargo/vendor/bytemuck-1.2.0/tests/cast_slice_tests.rs deleted file mode 100644 index 1177a7f..0000000 --- a/third_party/cargo/vendor/bytemuck-1.2.0/tests/cast_slice_tests.rs +++ /dev/null @@ -1,90 +0,0 @@ -use core::mem::size_of; - -use bytemuck::*; - -#[test] -fn test_try_cast_slice() { - // some align4 data - let u32_slice: &[u32] = &[4, 5, 6]; - // the same data as align1 - let the_bytes: &[u8] = try_cast_slice(u32_slice).unwrap(); - - assert_eq!( - u32_slice.as_ptr() as *const u32 as usize, - the_bytes.as_ptr() as *const u8 as usize - ); - assert_eq!( - u32_slice.len() * size_of::(), - the_bytes.len() * size_of::() - ); - - // by taking one byte off the front, we're definitely mis-aligned for u32. - let mis_aligned_bytes = &the_bytes[1..]; - assert_eq!( - try_cast_slice::(mis_aligned_bytes), - Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) - ); - - // by taking one byte off the end, we're aligned but would have slop bytes for u32 - let the_bytes_len_minus1 = the_bytes.len() - 1; - let slop_bytes = &the_bytes[..the_bytes_len_minus1]; - assert_eq!( - try_cast_slice::(slop_bytes), - Err(PodCastError::OutputSliceWouldHaveSlop) - ); - - // if we don't mess with it we can up-alignment cast - try_cast_slice::(the_bytes).unwrap(); -} - -#[test] -fn test_try_cast_slice_mut() { - // some align4 data - let u32_slice: &mut [u32] = &mut [4, 5, 6]; - let u32_len = u32_slice.len(); - let u32_ptr = u32_slice.as_ptr(); - - // the same data as align1 - let the_bytes: &mut [u8] = try_cast_slice_mut(u32_slice).unwrap(); - let the_bytes_len = the_bytes.len(); - let the_bytes_ptr = the_bytes.as_ptr(); - - assert_eq!( - u32_ptr as *const u32 as usize, - the_bytes_ptr as *const u8 as usize - ); - assert_eq!(u32_len * size_of::(), the_bytes_len * size_of::()); - - // by taking one byte off the front, we're definitely mis-aligned for u32. - let mis_aligned_bytes = &mut the_bytes[1..]; - assert_eq!( - try_cast_slice_mut::(mis_aligned_bytes), - Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) - ); - - // by taking one byte off the end, we're aligned but would have slop bytes for u32 - let the_bytes_len_minus1 = the_bytes.len() - 1; - let slop_bytes = &mut the_bytes[..the_bytes_len_minus1]; - assert_eq!( - try_cast_slice_mut::(slop_bytes), - Err(PodCastError::OutputSliceWouldHaveSlop) - ); - - // if we don't mess with it we can up-alignment cast - try_cast_slice_mut::(the_bytes).unwrap(); -} - -#[test] -fn test_types() { - let _: i32 = cast(1.0_f32); - let _: &mut i32 = cast_mut(&mut 1.0_f32); - let _: &i32 = cast_ref(&1.0_f32); - let _: &[i32] = cast_slice(&[1.0_f32]); - let _: &mut [i32] = cast_slice_mut(&mut [1.0_f32]); - // - let _: Result = try_cast(1.0_f32); - let _: Result<&mut i32, PodCastError> = try_cast_mut(&mut 1.0_f32); - let _: Result<&i32, PodCastError> = try_cast_ref(&1.0_f32); - let _: Result<&[i32], PodCastError> = try_cast_slice(&[1.0_f32]); - let _: Result<&mut [i32], PodCastError> = try_cast_slice_mut(&mut [1.0_f32]); -} diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/.cargo-checksum.json b/third_party/cargo/vendor/bytemuck-1.4.1/.cargo-checksum.json new file mode 100644 index 0000000..7b8f59b --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"6513cb751f90bc8cb94ecc29bcaaecbe4299e4d90f7d3ee207ff6b4504820ee5","LICENSE-APACHE":"e3ba223bb1423f0aad8c3dfce0fe3148db48926d41e6fbc3afbbf5ff9e1c89cb","LICENSE-MIT":"9df9ba60a11af705f2e451b53762686e615d86f76b169cf075c3237730dbd7e2","LICENSE-ZLIB":"84b34dd7608f7fb9b17bd588a6bf392bf7de504e2716f024a77d89f1b145a151","README.md":"d4c58e84661f23490ef8662cc6309b6eacf42ab939b19eaeae032c12febdd823","changelog.md":"b3592fcef45a96b2442ed1dfb2a00ffbf11578c9186be8177a3633d44a76fb9e","rustfmt.toml":"eeb0dc37ccf6e6a628fc0144cb8e7a9ebb197552cb739f9c75d6ab79ebee15db","src/allocation.rs":"c5f74c27d785cbf138159d80eb943fb16de4ff3ec0041da4fe23384b4578de16","src/contiguous.rs":"288aa77eca807f47d28c4372f6eb3fd87d885dcaf886fb725c10fdbaf1fd27d0","src/lib.rs":"ad43ebca9480fb8a68e8173d7d8949d2c38d95b746d0bd5e9b3c2d9208925aa1","src/offset_of.rs":"5d98aacb37ec5ce7df3809e15b2682ee1972248b1fb1c444bbb013bbd6d98bf1","src/pod.rs":"b64399dac0d0dcc6179b4da48c02a15dee881afe858d27aed58253775016f4da","src/transparent.rs":"f0475aaf00daf458ddd4f28e049ed72d46b8a86f9a9244a5aa1a0eb019657e21","src/zeroable.rs":"1fc0b80cee39b7171b8b9627c7e4fc4b369a17237910353feb6dbf9662944450","tests/cast_slice_tests.rs":"f1cacfc4ceeacafdc3acc1694c5579793c8f7c0908c5b2bde17a347453368657","tests/derive.rs":"0e5f4637fb11ab087e8b9cf76212caafa37e01cedba71cf4f51356187691b46a","tests/doc_tests.rs":"0008789fc7281f581c8c91eac13ea4683f82cdeadadc4119c7b21b38f7d41577","tests/offset_of_tests.rs":"bd9690a817b0ac36e07e4dce98e8de08f246d7f6d5ebd8df27a8a955c32db435","tests/std_tests.rs":"69661f26dc385c38d6c2bd37a62ba476e81ef88b4ed6565f3a47dd173133365c"},"package":"41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac"} \ No newline at end of file diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/BUILD.bazel b/third_party/cargo/vendor/bytemuck-1.4.1/BUILD.bazel new file mode 100644 index 0000000..cc4d3b4 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/BUILD.bazel @@ -0,0 +1,63 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Zlib from expression "Zlib OR (Apache-2.0 OR MIT)" +]) + +# Generated Targets + +rust_library( + name = "bytemuck", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.4.1", + # buildifier: leave-alone + deps = [ + ], +) + +# Unsupported target "cast_slice_tests" with type "test" omitted + +# Unsupported target "derive" with type "test" omitted + +# Unsupported target "doc_tests" with type "test" omitted + +# Unsupported target "offset_of_tests" with type "test" omitted + +# Unsupported target "std_tests" with type "test" omitted diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/Cargo.toml b/third_party/cargo/vendor/bytemuck-1.4.1/Cargo.toml new file mode 100644 index 0000000..3ceb9ed --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "bytemuck" +version = "1.4.1" +authors = ["Lokathor "] +exclude = ["/pedantic.bat"] +description = "A crate for mucking around with piles of bytes." +readme = "README.md" +keywords = ["transmute", "bytes", "casting"] +categories = ["encoding", "no-std"] +license = "Zlib OR Apache-2.0 OR MIT" +repository = "https://github.com/Lokathor/bytemuck" +[package.metadata.docs.rs] +all-features = true + +[package.metadata.playground] +all-features = true +[dependencies.bytemuck_derive] +version = "1" +optional = true + +[features] +derive = ["bytemuck_derive"] +extern_crate_alloc = [] +extern_crate_std = ["extern_crate_alloc"] +zeroable_maybe_uninit = [] diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-APACHE b/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-APACHE new file mode 100644 index 0000000..136d900 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-APACHE @@ -0,0 +1,61 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + + "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-MIT b/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-MIT new file mode 100644 index 0000000..164045f --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-MIT @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2019 Daniel "Lokathor" Gee. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/LICENSE-ZLIB.md b/third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-ZLIB similarity index 100% rename from third_party/cargo/vendor/bytemuck-1.2.0/LICENSE-ZLIB.md rename to third_party/cargo/vendor/bytemuck-1.4.1/LICENSE-ZLIB diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/README.md b/third_party/cargo/vendor/bytemuck-1.4.1/README.md new file mode 100644 index 0000000..7970d32 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/README.md @@ -0,0 +1,27 @@ +[![License:Zlib](https://img.shields.io/badge/License-Zlib-brightgreen.svg)](https://opensource.org/licenses/Zlib) +![Minimum Rust Version](https://img.shields.io/badge/Min%20Rust-1.34-green.svg) +[![crates.io](https://img.shields.io/crates/v/bytemuck.svg)](https://crates.io/crates/bytemuck) +[![docs.rs](https://docs.rs/bytemuck/badge.svg)](https://docs.rs/bytemuck/) + +# bytemuck + +A crate for mucking around with piles of bytes. + +## Extensions + +There is experimental support for the `Zeroable` trait being derived through a +proc-macro. I'm not the author of that crate, please file bugs with that crate +in the other repo. + +* https://github.com/rodrimati1992/zeroable_crates + +## Stability + +The goal is to stay at 1.y.z until _at least_ the next edition of Rust. + +I consider any increase of the Minimum Rust Version to be a semver breaking change, +so `rustc-1.34` will continue to be supported for at least the rest of the +`bytemuck-1.y.z` series of the crate. + +(The secret goal is to get all of this functionality into the standard library +some day so that we don't even need to import a crate to do all this fun stuff.) diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/changelog.md b/third_party/cargo/vendor/bytemuck-1.4.1/changelog.md new file mode 100644 index 0000000..a474435 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/changelog.md @@ -0,0 +1,62 @@ +# `bytemuck` changelog + +## 1.4 + +* [icewind1991](https://github.com/icewind1991) has contributed the proc-macros + for deriving impls of `Pod`, `TransparentWrapper`, `Zeroable`!! Everyone has + been waiting for this one folks! It's a big deal. Just enable the `derive` + cargo feature and then you'll be able to derive the traits on your types. It + generates all the appropriate tests for you. +* The `zeroable_maybe_uninit` feature now adds a `Zeroable` impl to the + `MaybeUninit` type. This is only behind a feature flag because `MaybeUninit` + didn't exist back in `1.34.0` (the minimum rust version of `bytemuck`). + +## 1.3.1 + +* The entire crate is now available under the `Apache-2.0 OR MIT` license as + well as the previous `Zlib` license + [#24](https://github.com/Lokathor/bytemuck/pull/24). +* [HeroicKatora](https://github.com/HeroicKatora) added the + `try_zeroed_slice_box` function + [#10](https://github.com/Lokathor/bytemuck/pull/17). `zeroed_slice_box` is + also available. +* The `offset_of!` macro now supports a 2-arg version. For types that impl + Default, it'll just make an instance using `default` and then call over to the + 3-arg version. +* The `PodCastError` type now supports `Hash` and `Display`. Also if you enable + the `extern_crate_std` feature then it will support `std::error::Error`. +* We now provide a `TransparentWrapper` impl for `core::num::Wrapper`. +* The error type of `try_from_bytes` and `try_from_bytes_mut` when the input + isn't aligned has been corrected from being `AlignmentMismatch` (intended for + allocation casting only) to `TargetAlignmentGreaterAndInputNotAligned`. + +## 1.3.0 + +* Had a bug because the CI was messed up! It wasn't soundness related, because + it prevented the crate from building entirely if the `extern_crate_alloc` + feature was used. Still, this is yanked, sorry. + +## 1.2.0 + +* [thomcc](https://github.com/thomcc) added many things: + * A fully sound `offset_of!` macro + [#10](https://github.com/Lokathor/bytemuck/pull/10) + * A `Contiguous` trait for when you've got enums with declared values + all in a row [#12](https://github.com/Lokathor/bytemuck/pull/12) + * A `TransparentWrapper` marker trait for when you want to more clearly + enable adding and removing a wrapper struct to its inner value + [#15](https://github.com/Lokathor/bytemuck/pull/15) + * Now MIRI is run on CI in every single push! + [#16](https://github.com/Lokathor/bytemuck/pull/16) + +## 1.1.0 + +* [SimonSapin](https://github.com/SimonSapin) added `from_bytes`, + `from_bytes_mut`, `try_from_bytes`, and `try_from_bytes_mut` ([PR + Link](https://github.com/Lokathor/bytemuck/pull/8)) + +## 1.0.1 + +* Changed to the [zlib](https://opensource.org/licenses/Zlib) license. +* Added much more proper documentation. +* Reduced the minimum Rust version to 1.34 diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/rustfmt.toml b/third_party/cargo/vendor/bytemuck-1.4.1/rustfmt.toml new file mode 100644 index 0000000..f214385 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/rustfmt.toml @@ -0,0 +1,16 @@ +# Based on +# https://github.com/rust-lang/rustfmt/blob/rustfmt-1.4.19/Configurations.md + +# Stable +edition = "2018" +fn_args_layout = "Compressed" +max_width = 80 +tab_spaces = 2 +use_field_init_shorthand = true +use_try_shorthand = true +use_small_heuristics = "Max" + +# Unstable +format_code_in_doc_comments = true +merge_imports = true +wrap_comments = true diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/src/allocation.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/allocation.rs new file mode 100644 index 0000000..06d62fa --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/src/allocation.rs @@ -0,0 +1,166 @@ +#![cfg(feature = "extern_crate_alloc")] + +//! Stuff to boost things in the `alloc` crate. +//! +//! * You must enable the `extern_crate_alloc` feature of `bytemuck` or you will +//! not be able to use this module! + +use super::*; +use alloc::{ + alloc::{alloc_zeroed, Layout}, + boxed::Box, + vec::Vec, +}; + +/// As [`try_cast_box`](try_cast_box), but unwraps for you. +#[inline] +pub fn cast_box(input: Box) -> Box { + try_cast_box(input).map_err(|(e, _v)| e).unwrap() +} + +/// Attempts to cast the content type of a [`Box`](alloc::boxed::Box). +/// +/// On failure you get back an error along with the starting `Box`. +/// +/// ## Failure +/// +/// * The start and end content type of the `Box` must have the exact same +/// alignment. +/// * The start and end size of the `Box` must have the exact same size. +#[inline] +pub fn try_cast_box( + input: Box, +) -> Result, (PodCastError, Box)> { + if align_of::() != align_of::() { + Err((PodCastError::AlignmentMismatch, input)) + } else if size_of::() != size_of::() { + Err((PodCastError::SizeMismatch, input)) + } else { + // Note(Lokathor): This is much simpler than with the Vec casting! + let ptr: *mut B = Box::into_raw(input) as *mut B; + Ok(unsafe { Box::from_raw(ptr) }) + } +} + +/// Allocates a `Box` with all of the contents being zeroed out. +/// +/// This uses the global allocator to create a zeroed allocation and _then_ +/// turns it into a Box. In other words, it's 100% assured that the zeroed data +/// won't be put temporarily on the stack. You can make a box of any size +/// without fear of a stack overflow. +/// +/// ## Failure +/// +/// This fails if the allocation fails. +#[inline] +pub fn try_zeroed_box() -> Result, ()> { + if size_of::() == 0 { + return Ok(Box::new(T::zeroed())); + } + let layout = + Layout::from_size_align(size_of::(), align_of::()).unwrap(); + let ptr = unsafe { alloc_zeroed(layout) }; + if ptr.is_null() { + // we don't know what the error is because `alloc_zeroed` is a dumb API + Err(()) + } else { + Ok(unsafe { Box::::from_raw(ptr as *mut T) }) + } +} + +/// As [`try_zeroed_box`], but unwraps for you. +#[inline] +pub fn zeroed_box() -> Box { + try_zeroed_box().unwrap() +} + +/// Allocates a `Box<[T]>` with all contents being zeroed out. +/// +/// This uses the global allocator to create a zeroed allocation and _then_ +/// turns it into a Box. In other words, it's 100% assured that the zeroed data +/// won't be put temporarily on the stack. You can make a box of any size +/// without fear of a stack overflow. +/// +/// ## Failure +/// +/// This fails if the allocation fails. +#[inline] +pub fn try_zeroed_slice_box( + length: usize, +) -> Result, ()> { + if size_of::() == 0 { + // This will not allocate but simple create a dangling slice pointer. + let mut vec = Vec::with_capacity(length); + vec.resize_with(length, || T::zeroed()); + return Ok(vec.into_boxed_slice()); + } + if length == 0 { + // This will also not allocate. + return Ok(Vec::new().into_boxed_slice()); + } + // For Pod types, the layout of the array/slice is equivalent to repeating the type. + let layout_length = size_of::().checked_mul(length).ok_or(())?; + assert!(layout_length != 0); + let layout = + Layout::from_size_align(layout_length, align_of::()).map_err(|_| ())?; + let ptr = unsafe { alloc_zeroed(layout) }; + if ptr.is_null() { + // we don't know what the error is because `alloc_zeroed` is a dumb API + Err(()) + } else { + let slice = + unsafe { core::slice::from_raw_parts_mut(ptr as *mut T, length) }; + Ok(unsafe { Box::<[T]>::from_raw(slice) }) + } +} + +/// As [`try_zeroed_slice_box`](try_zeroed_slice_box), but unwraps for you. +pub fn zeroed_slice_box(length: usize) -> Box<[T]> { + try_zeroed_slice_box(length).unwrap() +} + +/// As [`try_cast_vec`](try_cast_vec), but unwraps for you. +#[inline] +pub fn cast_vec(input: Vec) -> Vec { + try_cast_vec(input).map_err(|(e, _v)| e).unwrap() +} + +/// Attempts to cast the content type of a [`Vec`](alloc::vec::Vec). +/// +/// On failure you get back an error along with the starting `Vec`. +/// +/// ## Failure +/// +/// * The start and end content type of the `Vec` must have the exact same +/// alignment. +/// * The start and end size of the `Vec` must have the exact same size. +/// * In the future this second restriction might be lessened by having the +/// capacity and length get adjusted during transmutation, but for now it's +/// absolute. +#[inline] +pub fn try_cast_vec( + input: Vec, +) -> Result, (PodCastError, Vec)> { + if align_of::() != align_of::() { + Err((PodCastError::AlignmentMismatch, input)) + } else if size_of::() != size_of::() { + // Note(Lokathor): Under some conditions it would be possible to cast + // between Vec content types of the same alignment but different sizes by + // changing the capacity and len values in the output Vec. However, we will + // not attempt that for now. + Err((PodCastError::SizeMismatch, input)) + } else { + // Note(Lokathor): First we record the length and capacity, which don't have + // any secret provenance metadata. + let length: usize = input.len(); + let capacity: usize = input.capacity(); + // Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with + // ManuallyDrop, because if we used `core::mem::forget` after taking the + // pointer then that would invalidate our pointer. In nightly there's a + // "into raw parts" method, which we can switch this too eventually. + let mut manual_drop_vec = ManuallyDrop::new(input); + let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr(); + let ptr: *mut B = vec_ptr as *mut B; + Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) }) + } +} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/contiguous.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/contiguous.rs similarity index 100% rename from third_party/cargo/vendor/bytemuck-1.2.0/src/contiguous.rs rename to third_party/cargo/vendor/bytemuck-1.4.1/src/contiguous.rs diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/src/lib.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/lib.rs new file mode 100644 index 0000000..ccbdbda --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/src/lib.rs @@ -0,0 +1,442 @@ +#![no_std] +#![warn(missing_docs)] + +//! This crate gives small utilities for casting between plain data types. +//! +//! ## Basics +//! +//! Data comes in five basic forms in Rust, so we have five basic casting +//! functions: +//! +//! * `T` uses [`cast`] +//! * `&T` uses [`cast_ref`] +//! * `&mut T` uses [`cast_mut`] +//! * `&[T]` uses [`cast_slice`] +//! * `&mut [T]` uses [`cast_slice_mut`] +//! +//! Some casts will never fail (eg: `cast::` always works), other +//! casts might fail (eg: `cast_ref::<[u8; 4], u32>` will fail if the reference +//! isn't already aligned to 4). Each casting function has a "try" version which +//! will return a `Result`, and the "normal" version which will simply panic on +//! invalid input. +//! +//! ## Using Your Own Types +//! +//! All the functions here are guarded by the [`Pod`] trait, which is a +//! sub-trait of the [`Zeroable`] trait. +//! +//! If you're very sure that your type is eligible, you can implement those +//! traits for your type and then they'll have full casting support. However, +//! these traits are `unsafe`, and you should carefully read the requirements +//! before adding the them to your own types. +//! +//! ## Features +//! +//! * This crate is core only by default, but if you're using Rust 1.36 or later +//! you can enable the `extern_crate_alloc` cargo feature for some additional +//! methods related to `Box` and `Vec`. Note that the `docs.rs` documentation +//! is always built with `extern_crate_alloc` cargo feature enabled. + +#[cfg(target_arch = "x86")] +use core::arch::x86; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64; +// +use core::{marker::*, mem::*, num::*, ptr::*}; + +// Used from macros to ensure we aren't using some locally defined name and +// actually are referencing libcore. This also would allow pre-2018 edition +// crates to use our macros, but I'm not sure how important that is. +#[doc(hidden)] +pub use ::core as __core; + +macro_rules! impl_unsafe_marker_for_array { + ( $marker:ident , $( $n:expr ),* ) => { + $(unsafe impl $marker for [T; $n] where T: $marker {})* + } +} + +#[cfg(feature = "extern_crate_std")] +extern crate std; + +#[cfg(feature = "extern_crate_alloc")] +extern crate alloc; +#[cfg(feature = "extern_crate_alloc")] +pub mod allocation; +#[cfg(feature = "extern_crate_alloc")] +pub use allocation::*; + +mod zeroable; +pub use zeroable::*; + +mod pod; +pub use pod::*; + +mod contiguous; +pub use contiguous::*; + +mod offset_of; +pub use offset_of::*; + +mod transparent; +pub use transparent::*; + +#[cfg(feature = "derive")] +pub use bytemuck_derive::{Zeroable, Pod, TransparentWrapper, Contiguous}; + +/* + +Note(Lokathor): We've switched all of the `unwrap` to `match` because there is +apparently a bug: https://github.com/rust-lang/rust/issues/68667 +and it doesn't seem to show up in simple godbolt examples but has been reported +as having an impact when there's a cast mixed in with other more complicated +code around it. Rustc/LLVM ends up missing that the `Err` can't ever happen for +particular type combinations, and then it doesn't fully eliminated the panic +possibility code branch. + +*/ + +/// Immediately panics. +#[cold] +#[inline(never)] +fn something_went_wrong(src: &str, err: PodCastError) -> ! { + // Note(Lokathor): Keeping the panic here makes the panic _formatting_ go + // here too, which helps assembly readability and also helps keep down + // the inline pressure. + panic!("{src}>{err:?}", src = src, err = err) +} + +/// Re-interprets `&T` as `&[u8]`. +/// +/// Any ZST becomes an empty slice, and in that case the pointer value of that +/// empty slice might not match the pointer value of the input reference. +#[inline] +pub fn bytes_of(t: &T) -> &[u8] { + match try_cast_slice::(core::slice::from_ref(t)) { + Ok(s) => s, + Err(_) => unreachable!(), + } +} + +/// Re-interprets `&mut T` as `&mut [u8]`. +/// +/// Any ZST becomes an empty slice, and in that case the pointer value of that +/// empty slice might not match the pointer value of the input reference. +#[inline] +pub fn bytes_of_mut(t: &mut T) -> &mut [u8] { + match try_cast_slice_mut::(core::slice::from_mut(t)) { + Ok(s) => s, + Err(_) => unreachable!(), + } +} + +/// Re-interprets `&[u8]` as `&T`. +/// +/// ## Panics +/// +/// This is [`try_from_bytes`] but will panic on error. +#[inline] +pub fn from_bytes(s: &[u8]) -> &T { + match try_from_bytes(s) { + Ok(t) => t, + Err(e) => something_went_wrong("from_bytes", e), + } +} + +/// Re-interprets `&mut [u8]` as `&mut T`. +/// +/// ## Panics +/// +/// This is [`try_from_bytes_mut`] but will panic on error. +#[inline] +pub fn from_bytes_mut(s: &mut [u8]) -> &mut T { + match try_from_bytes_mut(s) { + Ok(t) => t, + Err(e) => something_went_wrong("from_bytes_mut", e), + } +} + +/// Re-interprets `&[u8]` as `&T`. +/// +/// ## Failure +/// +/// * If the slice isn't aligned for the new type +/// * If the slice's length isn’t exactly the size of the new type +#[inline] +pub fn try_from_bytes(s: &[u8]) -> Result<&T, PodCastError> { + if s.len() != size_of::() { + Err(PodCastError::SizeMismatch) + } else if (s.as_ptr() as usize) % align_of::() != 0 { + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + } else { + Ok(unsafe { &*(s.as_ptr() as *const T) }) + } +} + +/// Re-interprets `&mut [u8]` as `&mut T`. +/// +/// ## Failure +/// +/// * If the slice isn't aligned for the new type +/// * If the slice's length isn’t exactly the size of the new type +#[inline] +pub fn try_from_bytes_mut( + s: &mut [u8], +) -> Result<&mut T, PodCastError> { + if s.len() != size_of::() { + Err(PodCastError::SizeMismatch) + } else if (s.as_ptr() as usize) % align_of::() != 0 { + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + } else { + Ok(unsafe { &mut *(s.as_mut_ptr() as *mut T) }) + } +} + +/// The things that can go wrong when casting between [`Pod`] data forms. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum PodCastError { + /// You tried to cast a slice to an element type with a higher alignment + /// requirement but the slice wasn't aligned. + TargetAlignmentGreaterAndInputNotAligned, + /// If the element size changes then the output slice changes length + /// accordingly. If the output slice wouldn't be a whole number of elements + /// then the conversion fails. + OutputSliceWouldHaveSlop, + /// When casting a slice you can't convert between ZST elements and non-ZST + /// elements. When casting an individual `T`, `&T`, or `&mut T` value the + /// source size and destination size must be an exact match. + SizeMismatch, + /// For this type of cast the alignments must be exactly the same and they + /// were not so now you're sad. + /// + /// This error is generated **only** by operations that cast allocated types + /// (such as `Box` and `Vec`), because in that case the alignment must stay + /// exact. + AlignmentMismatch, +} +impl core::fmt::Display for PodCastError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{:?}", self) + } +} +#[cfg(feature = "extern_crate_std")] +impl std::error::Error for PodCastError {} + +/// Cast `T` into `U` +/// +/// ## Panics +/// +/// * This is like [`try_cast`](try_cast), but will panic on a size mismatch. +#[inline] +pub fn cast(a: A) -> B { + if size_of::() == size_of::() { + unsafe { core::mem::transmute_copy(&a) } + } else { + something_went_wrong("cast", PodCastError::SizeMismatch) + } +} + +/// Cast `&mut T` into `&mut U`. +/// +/// ## Panics +/// +/// This is [`try_cast_mut`] but will panic on error. +#[inline] +pub fn cast_mut(a: &mut A) -> &mut B { + if size_of::() == size_of::() && align_of::() >= align_of::() { + // Plz mr compiler, just notice that we can't ever hit Err in this case. + match try_cast_mut(a) { + Ok(b) => b, + Err(_) => unreachable!(), + } + } else { + match try_cast_mut(a) { + Ok(b) => b, + Err(e) => something_went_wrong("cast_mut", e), + } + } +} + +/// Cast `&T` into `&U`. +/// +/// ## Panics +/// +/// This is [`try_cast_ref`] but will panic on error. +#[inline] +pub fn cast_ref(a: &A) -> &B { + if size_of::() == size_of::() && align_of::() >= align_of::() { + // Plz mr compiler, just notice that we can't ever hit Err in this case. + match try_cast_ref(a) { + Ok(b) => b, + Err(_) => unreachable!(), + } + } else { + match try_cast_ref(a) { + Ok(b) => b, + Err(e) => something_went_wrong("cast_ref", e), + } + } +} + +/// Cast `&[A]` into `&[B]`. +/// +/// ## Panics +/// +/// This is [`try_cast_slice`] but will panic on error. +#[inline] +pub fn cast_slice(a: &[A]) -> &[B] { + match try_cast_slice(a) { + Ok(b) => b, + Err(e) => something_went_wrong("cast_slice", e), + } +} + +/// Cast `&mut [T]` into `&mut [U]`. +/// +/// ## Panics +/// +/// This is [`try_cast_slice_mut`] but will panic on error. +#[inline] +pub fn cast_slice_mut(a: &mut [A]) -> &mut [B] { + match try_cast_slice_mut(a) { + Ok(b) => b, + Err(e) => something_went_wrong("cast_slice_mut", e), + } +} + +/// As `align_to`, but safe because of the [`Pod`] bound. +#[inline] +pub fn pod_align_to(vals: &[T]) -> (&[T], &[U], &[T]) { + unsafe { vals.align_to::() } +} + +/// As `align_to_mut`, but safe because of the [`Pod`] bound. +#[inline] +pub fn pod_align_to_mut( + vals: &mut [T], +) -> (&mut [T], &mut [U], &mut [T]) { + unsafe { vals.align_to_mut::() } +} + +/// Try to cast `T` into `U`. +/// +/// Note that for this particular type of cast, alignment isn't a factor. The +/// input value is semantically copied into the function and then returned to a +/// new memory location which will have whatever the required alignment of the +/// output type is. +/// +/// ## Failure +/// +/// * If the types don't have the same size this fails. +#[inline] +pub fn try_cast(a: A) -> Result { + if size_of::() == size_of::() { + Ok(unsafe { core::mem::transmute_copy(&a) }) + } else { + Err(PodCastError::SizeMismatch) + } +} + +/// Try to convert a `&T` into `&U`. +/// +/// ## Failure +/// +/// * If the reference isn't aligned in the new type +/// * If the source type and target type aren't the same size. +#[inline] +pub fn try_cast_ref(a: &A) -> Result<&B, PodCastError> { + // Note(Lokathor): everything with `align_of` and `size_of` will optimize away + // after monomorphization. + if align_of::() > align_of::() + && (a as *const A as usize) % align_of::() != 0 + { + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + } else if size_of::() == size_of::() { + Ok(unsafe { &*(a as *const A as *const B) }) + } else { + Err(PodCastError::SizeMismatch) + } +} + +/// Try to convert a `&mut T` into `&mut U`. +/// +/// As [`try_cast_ref`], but `mut`. +#[inline] +pub fn try_cast_mut(a: &mut A) -> Result<&mut B, PodCastError> { + // Note(Lokathor): everything with `align_of` and `size_of` will optimize away + // after monomorphization. + if align_of::() > align_of::() + && (a as *mut A as usize) % align_of::() != 0 + { + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + } else if size_of::() == size_of::() { + Ok(unsafe { &mut *(a as *mut A as *mut B) }) + } else { + Err(PodCastError::SizeMismatch) + } +} + +/// Try to convert `&[A]` into `&[B]` (possibly with a change in length). +/// +/// * `input.as_ptr() as usize == output.as_ptr() as usize` +/// * `input.len() * size_of::() == output.len() * size_of::()` +/// +/// ## Failure +/// +/// * If the target type has a greater alignment requirement and the input slice +/// isn't aligned. +/// * If the target element type is a different size from the current element +/// type, and the output slice wouldn't be a whole number of elements when +/// accounting for the size change (eg: 3 `u16` values is 1.5 `u32` values, so +/// that's a failure). +/// * Similarly, you can't convert between a [ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts) +/// and a non-ZST. +#[inline] +pub fn try_cast_slice(a: &[A]) -> Result<&[B], PodCastError> { + // Note(Lokathor): everything with `align_of` and `size_of` will optimize away + // after monomorphization. + if align_of::() > align_of::() + && (a.as_ptr() as usize) % align_of::() != 0 + { + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + } else if size_of::() == size_of::() { + Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, a.len()) }) + } else if size_of::() == 0 || size_of::() == 0 { + Err(PodCastError::SizeMismatch) + } else if core::mem::size_of_val(a) % size_of::() == 0 { + let new_len = core::mem::size_of_val(a) / size_of::(); + Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) }) + } else { + Err(PodCastError::OutputSliceWouldHaveSlop) + } +} + +/// Try to convert `&mut [A]` into `&mut [B]` (possibly with a change in +/// length). +/// +/// As [`try_cast_slice`], but `&mut`. +#[inline] +pub fn try_cast_slice_mut( + a: &mut [A], +) -> Result<&mut [B], PodCastError> { + // Note(Lokathor): everything with `align_of` and `size_of` will optimize away + // after monomorphization. + if align_of::() > align_of::() + && (a.as_mut_ptr() as usize) % align_of::() != 0 + { + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + } else if size_of::() == size_of::() { + Ok(unsafe { + core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len()) + }) + } else if size_of::() == 0 || size_of::() == 0 { + Err(PodCastError::SizeMismatch) + } else if core::mem::size_of_val(a) % size_of::() == 0 { + let new_len = core::mem::size_of_val(a) / size_of::(); + Ok(unsafe { + core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) + }) + } else { + Err(PodCastError::OutputSliceWouldHaveSlop) + } +} diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/src/offset_of.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/offset_of.rs new file mode 100644 index 0000000..604379a --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/src/offset_of.rs @@ -0,0 +1,132 @@ +#![forbid(unsafe_code)] + +/// Find the offset in bytes of the given `$field` of `$Type`. Requires an +/// already initialized `$instance` value to work with. +/// +/// This is similar to the macro from [`memoffset`](https://docs.rs/memoffset), +/// however it uses no `unsafe` code. +/// +/// This macro has a 3-argument and 2-argument version. +/// * In the 3-arg version you specify an instance of the type, the type itself, +/// and the field name. +/// * In the 2-arg version the macro will call the [`default`](Default::default) +/// method to make a temporary instance of the type for you. +/// +/// The output of this macro is the byte offset of the field (as a `usize`). The +/// calculations of the macro are fixed across the entire program, but if the +/// type used is `repr(Rust)` then they're *not* fixed across compilations or +/// compilers. +/// +/// ## Examples +/// +/// ### 3-arg Usage +/// +/// ```rust +/// # use bytemuck::offset_of; +/// // enums can't derive default, and for this example we don't pick one +/// enum MyExampleEnum { +/// A, B, C, +/// } +/// +/// // so now our struct here doesn't have Default +/// #[repr(C)] +/// struct MyNotDefaultType { +/// pub counter: i32, +/// pub some_field: MyExampleEnum, +/// } +/// +/// // but we provide an instance of the type and it's all good. +/// let val = MyNotDefaultType { counter: 5, some_field: MyExampleEnum::A }; +/// assert_eq!(offset_of!(val, MyNotDefaultType, some_field), 4); +/// ``` +/// +/// ### 2-arg Usage +/// +/// ```rust +/// # use bytemuck::offset_of; +/// #[derive(Default)] +/// #[repr(C)] +/// struct Vertex { +/// pub loc: [f32; 3], +/// pub color: [f32; 3], +/// } +/// // if the type impls Default the macro can make its own default instance. +/// assert_eq!(offset_of!(Vertex, loc), 0); +/// assert_eq!(offset_of!(Vertex, color), 12); +/// ``` +/// +/// # Usage with `#[repr(packed)]` structs +/// +/// Attempting to compute the offset of a `#[repr(packed)]` struct with +/// `bytemuck::offset_of!` requires an `unsafe` block. We hope to relax this in +/// the future, but currently it is required to work around a soundness hole in +/// Rust (See [rust-lang/rust#27060]). +/// +/// [rust-lang/rust#27060]: https://github.com/rust-lang/rust/issues/27060 +/// +///

+/// Warning: This is only true for versions of bytemuck > 1.4.0. +/// Previous versions of +/// bytemuck::offset_of! +/// will only emit a warning when used on the field of a packed struct in safe code, +/// which can lead to unsoundness. +///

+/// +/// For example, the following will fail to compile: +/// +/// ```compile_fail +/// #[repr(C, packed)] +/// #[derive(Default)] +/// struct Example { +/// field: u32, +/// } +/// // Doesn't compile: +/// let _offset = bytemuck::offset_of!(Example, field); +/// ``` +/// +/// While the error message this generates will mention the +/// `safe_packed_borrows` lint, the macro will still fail to compile even if +/// that lint is `#[allow]`ed: +/// +/// ```compile_fail +/// # #[repr(C, packed)] #[derive(Default)] struct Example { field: u32 } +/// // Still doesn't compile: +/// #[allow(safe_packed_borrows)] { +/// let _offset = bytemuck::offset_of!(Example, field); +/// } +/// ``` +/// +/// This *can* be worked around by using `unsafe`, but it is only sound to do so +/// if you can guarantee that taking a reference to the field is sound. +/// +/// In practice, this means it only works for fields of align(1) types, or if +/// you know the field's offset in advance (defeating the point of `offset_of`) +/// and can prove that the struct's alignment and the field's offset are enough +/// to prove the field's alignment. +/// +/// Once the `raw_ref` macros are available, a future version of this crate will +/// use them to lift the limitations of packed structs. For the duration of the +/// `1.x` version of this crate that will be behind an on-by-default cargo +/// feature (to maintain minimum rust version support). +#[macro_export] +macro_rules! offset_of { + ($instance:expr, $Type:path, $field:tt) => {{ + #[forbid(safe_packed_borrows)] + { + // This helps us guard against field access going through a Deref impl. + #[allow(clippy::unneeded_field_pattern)] + let $Type { $field: _, .. }; + let reference: &$Type = &$instance; + let address = reference as *const _ as usize; + let field_pointer = &reference.$field as *const _ as usize; + // These asserts/unwraps are compiled away at release, and defend against + // the case where somehow a deref impl is still invoked. + let result = field_pointer.checked_sub(address).unwrap(); + assert!(result <= $crate::__core::mem::size_of::<$Type>()); + result + } + }}; + ($Type:path, $field:tt) => {{ + $crate::offset_of!(<$Type as Default>::default(), $Type, $field) + }}; +} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/pod.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/pod.rs similarity index 100% rename from third_party/cargo/vendor/bytemuck-1.2.0/src/pod.rs rename to third_party/cargo/vendor/bytemuck-1.4.1/src/pod.rs diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/src/transparent.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/transparent.rs new file mode 100644 index 0000000..fa6d479 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/src/transparent.rs @@ -0,0 +1,135 @@ +use super::*; + +/// A trait which indicates that a type is a `repr(transparent)` wrapper around +/// the `Wrapped` value. +/// +/// This allows safely creating references to `T` from those to the `Wrapped` +/// type, using the `wrap_ref` and `wrap_mut` functions. +/// +/// # Safety +/// +/// The safety contract of `TransparentWrapper` is relatively simple: +/// +/// For a given `Wrapper` which implements `TransparentWrapper`: +/// +/// 1. Wrapper must be a `#[repr(transparent)]` wrapper around `Wrapped`. This +/// either means that it must be a `#[repr(transparent)]` struct which +/// contains a either a field of type `Wrapped` (or a field of some other +/// transparent wrapper for `Wrapped`) as the only non-ZST field. +/// +/// 2. Any fields *other* than the `Wrapped` field must be trivially +/// constructable ZSTs, for example `PhantomData`, `PhantomPinned`, etc. +/// +/// 3. The `Wrapper` may not impose additional alignment requirements over +/// `Wrapped`. +/// - Note: this is currently guaranteed by `repr(transparent)`, but there +/// have been discussions of lifting it, so it's stated here explicitly. +/// +/// 4. The `wrap_ref` and `wrap_mut` functions on `TransparentWrapper` may not +/// be overridden. +/// +/// ## Caveats +/// +/// If the wrapper imposes additional constraints upon the wrapped type which +/// are required for safety, it's responsible for ensuring those still hold -- +/// this generally requires preventing access to instances of the wrapped type, +/// as implementing `TransparentWrapper for T` means anybody can call +/// `T::cast_ref(any_instance_of_u)`. +/// +/// For example, it would be invalid to implement TransparentWrapper for `str` +/// to implement `TransparentWrapper` around `[u8]` because of this. +/// +/// # Examples +/// +/// ## Basic +/// +/// ``` +/// use bytemuck::TransparentWrapper; +/// # #[derive(Default)] +/// # struct SomeStruct(u32); +/// +/// #[repr(transparent)] +/// struct MyWrapper(SomeStruct); +/// +/// unsafe impl TransparentWrapper for MyWrapper {} +/// +/// // interpret a reference to &SomeStruct as a &MyWrapper +/// let thing = SomeStruct::default(); +/// let wrapped_ref: &MyWrapper = MyWrapper::wrap_ref(&thing); +/// +/// // Works with &mut too. +/// let mut mut_thing = SomeStruct::default(); +/// let wrapped_mut: &mut MyWrapper = MyWrapper::wrap_mut(&mut mut_thing); +/// +/// # let _ = (wrapped_ref, wrapped_mut); // silence warnings +/// ``` +/// +/// ## Use with dynamically sized types +/// +/// ``` +/// use bytemuck::TransparentWrapper; +/// +/// #[repr(transparent)] +/// struct Slice([T]); +/// +/// unsafe impl TransparentWrapper<[T]> for Slice {} +/// +/// let s = Slice::wrap_ref(&[1u32, 2, 3]); +/// assert_eq!(&s.0, &[1, 2, 3]); +/// +/// let mut buf = [1, 2, 3u8]; +/// let sm = Slice::wrap_mut(&mut buf); +/// ``` +pub unsafe trait TransparentWrapper { + /// Convert a reference to a wrapped type into a reference to the wrapper. + /// + /// This is a trait method so that you can write `MyType::wrap_ref(...)` in + /// your code. It is part of the safety contract for this trait that if you + /// implement `TransparentWrapper<_>` for your type you **must not** override + /// this method. + #[inline] + fn wrap_ref(s: &Wrapped) -> &Self { + unsafe { + assert!(size_of::<*const Wrapped>() == size_of::<*const Self>()); + // Using a pointer cast doesn't work here because rustc can't tell that the + // vtables match (if we lifted the ?Sized restriction, this would go away), + // and transmute doesn't work for the usual reasons it doesn't work inside + // generic functions. + // + // SAFETY: The unsafe contract requires that these have identical + // representations. Using this transmute_copy instead of transmute here is + // annoying, but is required as `Self` and `Wrapped` have unspecified + // sizes still. + let wrapped_ptr = s as *const Wrapped; + let wrapper_ptr: *const Self = transmute_copy(&wrapped_ptr); + &*wrapper_ptr + } + } + + /// Convert a mut reference to a wrapped type into a mut reference to the + /// wrapper. + /// + /// This is a trait method so that you can write `MyType::wrap_mut(...)` in + /// your code. It is part of the safety contract for this trait that if you implement + /// `TransparentWrapper<_>` for your type you **must not** override this method. + #[inline] + fn wrap_mut(s: &mut Wrapped) -> &mut Self { + unsafe { + assert!(size_of::<*mut Wrapped>() == size_of::<*mut Self>()); + // Using a pointer cast doesn't work here because rustc can't tell that the + // vtables match (if we lifted the ?Sized restriction, this would go away), + // and transmute doesn't work for the usual reasons it doesn't work inside + // generic functions. + // + // SAFETY: The unsafe contract requires that these have identical + // representations. Using this transmute_copy instead of transmute here is + // annoying, but is required as `Self` and `Wrapped` have unspecified + // sizes still. + let wrapped_ptr = s as *mut Wrapped; + let wrapper_ptr: *mut Self = transmute_copy(&wrapped_ptr); + &mut *wrapper_ptr + } + } +} + +unsafe impl TransparentWrapper for core::num::Wrapping {} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/src/zeroable.rs b/third_party/cargo/vendor/bytemuck-1.4.1/src/zeroable.rs similarity index 97% rename from third_party/cargo/vendor/bytemuck-1.2.0/src/zeroable.rs rename to third_party/cargo/vendor/bytemuck-1.4.1/src/zeroable.rs index fb96204..ebd412f 100644 --- a/third_party/cargo/vendor/bytemuck-1.2.0/src/zeroable.rs +++ b/third_party/cargo/vendor/bytemuck-1.4.1/src/zeroable.rs @@ -61,8 +61,8 @@ unsafe impl Zeroable for Option> {} unsafe impl Zeroable for PhantomData {} unsafe impl Zeroable for ManuallyDrop {} -// 2.0: add MaybeUninit -//unsafe impl Zeroable for MaybeUninit {} +#[cfg(feature = "zeroable_maybe_uninit")] +unsafe impl Zeroable for core::mem::MaybeUninit {} unsafe impl Zeroable for (A,) {} unsafe impl Zeroable for (A, B) {} diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/tests/cast_slice_tests.rs b/third_party/cargo/vendor/bytemuck-1.4.1/tests/cast_slice_tests.rs new file mode 100644 index 0000000..9eb08c5 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/tests/cast_slice_tests.rs @@ -0,0 +1,165 @@ +use core::mem::size_of; + +use bytemuck::*; + +#[test] +fn test_try_cast_slice() { + // some align4 data + let u32_slice: &[u32] = &[4, 5, 6]; + // the same data as align1 + let the_bytes: &[u8] = try_cast_slice(u32_slice).unwrap(); + + assert_eq!( + u32_slice.as_ptr() as *const u32 as usize, + the_bytes.as_ptr() as *const u8 as usize + ); + assert_eq!( + u32_slice.len() * size_of::(), + the_bytes.len() * size_of::() + ); + + // by taking one byte off the front, we're definitely mis-aligned for u32. + let mis_aligned_bytes = &the_bytes[1..]; + assert_eq!( + try_cast_slice::(mis_aligned_bytes), + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + ); + + // by taking one byte off the end, we're aligned but would have slop bytes for u32 + let the_bytes_len_minus1 = the_bytes.len() - 1; + let slop_bytes = &the_bytes[..the_bytes_len_minus1]; + assert_eq!( + try_cast_slice::(slop_bytes), + Err(PodCastError::OutputSliceWouldHaveSlop) + ); + + // if we don't mess with it we can up-alignment cast + try_cast_slice::(the_bytes).unwrap(); +} + +#[test] +fn test_try_cast_slice_mut() { + // some align4 data + let u32_slice: &mut [u32] = &mut [4, 5, 6]; + let u32_len = u32_slice.len(); + let u32_ptr = u32_slice.as_ptr(); + + // the same data as align1 + let the_bytes: &mut [u8] = try_cast_slice_mut(u32_slice).unwrap(); + let the_bytes_len = the_bytes.len(); + let the_bytes_ptr = the_bytes.as_ptr(); + + assert_eq!( + u32_ptr as *const u32 as usize, + the_bytes_ptr as *const u8 as usize + ); + assert_eq!(u32_len * size_of::(), the_bytes_len * size_of::()); + + // by taking one byte off the front, we're definitely mis-aligned for u32. + let mis_aligned_bytes = &mut the_bytes[1..]; + assert_eq!( + try_cast_slice_mut::(mis_aligned_bytes), + Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) + ); + + // by taking one byte off the end, we're aligned but would have slop bytes for u32 + let the_bytes_len_minus1 = the_bytes.len() - 1; + let slop_bytes = &mut the_bytes[..the_bytes_len_minus1]; + assert_eq!( + try_cast_slice_mut::(slop_bytes), + Err(PodCastError::OutputSliceWouldHaveSlop) + ); + + // if we don't mess with it we can up-alignment cast + try_cast_slice_mut::(the_bytes).unwrap(); +} + +#[test] +fn test_types() { + let _: i32 = cast(1.0_f32); + let _: &mut i32 = cast_mut(&mut 1.0_f32); + let _: &i32 = cast_ref(&1.0_f32); + let _: &[i32] = cast_slice(&[1.0_f32]); + let _: &mut [i32] = cast_slice_mut(&mut [1.0_f32]); + // + let _: Result = try_cast(1.0_f32); + let _: Result<&mut i32, PodCastError> = try_cast_mut(&mut 1.0_f32); + let _: Result<&i32, PodCastError> = try_cast_ref(&1.0_f32); + let _: Result<&[i32], PodCastError> = try_cast_slice(&[1.0_f32]); + let _: Result<&mut [i32], PodCastError> = try_cast_slice_mut(&mut [1.0_f32]); +} + +#[test] +fn test_bytes_of() { + assert_eq!(bytes_of(&0xaabbccdd_u32), &0xaabbccdd_u32.to_ne_bytes()); + assert_eq!(bytes_of_mut(&mut 0xaabbccdd_u32), &mut 0xaabbccdd_u32.to_ne_bytes()); + let mut a = 0xaabbccdd_u32; + let a_addr = &a as *const _ as usize; + // ensure addresses match. + assert_eq!(bytes_of(&a).as_ptr() as usize, a_addr); + assert_eq!(bytes_of_mut(&mut a).as_ptr() as usize, a_addr); +} + +#[test] +fn test_try_from_bytes() { + let u32s = [0xaabbccdd, 0x11223344_u32]; + let bytes = bytemuck::cast_slice::(&u32s); + assert_eq!(try_from_bytes::(&bytes[..4]), Ok(&u32s[0])); + assert_eq!(try_from_bytes::(&bytes[..5]), Err(PodCastError::SizeMismatch)); + assert_eq!(try_from_bytes::(&bytes[..3]), Err(PodCastError::SizeMismatch)); + assert_eq!(try_from_bytes::(&bytes[1..5]), Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)); +} + +#[test] +fn test_try_from_bytes_mut() { + let mut abcd = 0xaabbccdd; + let mut u32s = [abcd, 0x11223344_u32]; + let bytes = bytemuck::cast_slice_mut::(&mut u32s); + assert_eq!(try_from_bytes_mut::(&mut bytes[..4]), Ok(&mut abcd)); + assert_eq!(try_from_bytes_mut::(&mut bytes[..4]), Ok(&mut abcd)); + assert_eq!(try_from_bytes_mut::(&mut bytes[..5]), Err(PodCastError::SizeMismatch)); + assert_eq!(try_from_bytes_mut::(&mut bytes[..3]), Err(PodCastError::SizeMismatch)); + assert_eq!(try_from_bytes::(&mut bytes[1..5]), Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)); +} + +#[test] +fn test_from_bytes() { + let abcd = 0xaabbccdd_u32; + let aligned_bytes = bytemuck::bytes_of(&abcd); + assert_eq!(from_bytes::(aligned_bytes), &abcd); + assert!(core::ptr::eq(from_bytes(aligned_bytes), &abcd)); +} + +#[test] +fn test_from_bytes_mut() { + let mut a = 0xaabbccdd_u32; + let a_addr = &a as *const _ as usize; + let aligned_bytes = bytemuck::bytes_of_mut(&mut a); + assert_eq!(*from_bytes_mut::(aligned_bytes), 0xaabbccdd_u32); + assert_eq!(from_bytes_mut::(aligned_bytes) as *const u32 as usize, a_addr); +} + +// like #[should_panic], but can be a part of another test, instead of requiring +// it to be it's own test. +macro_rules! should_panic { + ($ex:expr) => { + assert!( + std::panic::catch_unwind(|| { let _ = $ex; }).is_err(), + concat!("should have panicked: `", stringify!($ex), "`") + ); + }; +} + +#[test] +fn test_panics() { + should_panic!(cast_slice::(&[1u8, 2u8])); + should_panic!(cast_slice_mut::(&mut [1u8, 2u8])); + should_panic!(from_bytes::(&[1u8, 2])); + should_panic!(from_bytes::(&[1u8, 2, 3, 4, 5])); + should_panic!(from_bytes_mut::(&mut [1u8, 2])); + should_panic!(from_bytes_mut::(&mut [1u8, 2, 3, 4, 5])); + // use cast_slice on some u32s to get some align>=4 bytes, so we can know + // we'll give from_bytes unaligned ones. + let aligned_bytes = bytemuck::cast_slice::(&[0, 0]); + should_panic!(from_bytes::(&aligned_bytes[1..5])); +} diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/tests/derive.rs b/third_party/cargo/vendor/bytemuck-1.4.1/tests/derive.rs new file mode 100644 index 0000000..1e1deeb --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/tests/derive.rs @@ -0,0 +1,25 @@ +#![cfg(feature = "derive")] +#![allow(dead_code)] + +use bytemuck::{Zeroable, Pod, TransparentWrapper}; + +#[derive(Copy, Clone, Pod, Zeroable)] +#[repr(C)] +struct Test { + a: u16, + b: u16, +} + +#[derive(TransparentWrapper)] +#[repr(transparent)] +struct TransparentSingle { + a: u16, +} + +#[derive(TransparentWrapper)] +#[repr(transparent)] +#[transparent(u16)] +struct TransparentWithZeroSized { + a: u16, + b: () +} \ No newline at end of file diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/tests/doc_tests.rs b/third_party/cargo/vendor/bytemuck-1.4.1/tests/doc_tests.rs similarity index 100% rename from third_party/cargo/vendor/bytemuck-1.2.0/tests/doc_tests.rs rename to third_party/cargo/vendor/bytemuck-1.4.1/tests/doc_tests.rs diff --git a/third_party/cargo/vendor/bytemuck-1.4.1/tests/offset_of_tests.rs b/third_party/cargo/vendor/bytemuck-1.4.1/tests/offset_of_tests.rs new file mode 100644 index 0000000..b957514 --- /dev/null +++ b/third_party/cargo/vendor/bytemuck-1.4.1/tests/offset_of_tests.rs @@ -0,0 +1,59 @@ +use bytemuck::{offset_of, Zeroable}; + +#[test] +fn test_offset_of_vertex() { + #[repr(C)] + struct Vertex { + pos: [f32; 2], + uv: [u16; 2], + color: [u8; 4], + } + unsafe impl Zeroable for Vertex {} + + let pos = offset_of!(Zeroable::zeroed(), Vertex, pos); + let uv = offset_of!(Zeroable::zeroed(), Vertex, uv); + let color = offset_of!(Zeroable::zeroed(), Vertex, color); + + assert_eq!(pos, 0); + assert_eq!(uv, 8); + assert_eq!(color, 12); +} + +#[test] +fn test_offset_of_foo() { + #[derive(Default)] + struct Foo { + a: u8, + b: &'static str, + c: i32, + } + + let a_offset = offset_of!(Default::default(), Foo, a); + let b_offset = offset_of!(Default::default(), Foo, b); + let c_offset = offset_of!(Default::default(), Foo, c); + + assert_ne!(a_offset, b_offset); + assert_ne!(b_offset, c_offset); + // We can't check against hardcoded values for a repr(Rust) type, + // but prove to ourself this way. + + let foo = Foo::default(); + // Note: offsets are in bytes. + let as_bytes = &foo as *const _ as *const u8; + + // we're using wrapping_offset here because it's not worth + // the unsafe block, but it would be valid to use `add` instead, + // as it cannot overflow. + assert_eq!( + &foo.a as *const _ as usize, + as_bytes.wrapping_add(a_offset) as usize + ); + assert_eq!( + &foo.b as *const _ as usize, + as_bytes.wrapping_add(b_offset) as usize + ); + assert_eq!( + &foo.c as *const _ as usize, + as_bytes.wrapping_add(c_offset) as usize + ); +} diff --git a/third_party/cargo/vendor/bytemuck-1.2.0/tests/std_tests.rs b/third_party/cargo/vendor/bytemuck-1.4.1/tests/std_tests.rs similarity index 100% rename from third_party/cargo/vendor/bytemuck-1.2.0/tests/std_tests.rs rename to third_party/cargo/vendor/bytemuck-1.4.1/tests/std_tests.rs diff --git a/third_party/cargo/vendor/calloop-0.4.4/.cargo-checksum.json b/third_party/cargo/vendor/calloop-0.4.4/.cargo-checksum.json deleted file mode 100644 index 8120dfc..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"db77b3b5afe8c377f18724aaea479d9e94f0f7edc3b0a845af0836c7ad3ef789","Cargo.toml":"bad1b5b8ca1bc7b5dfd1110d3fd480e3f49e14e55a5edf5a1c664e785cb9953b","LICENSE.txt":"4b71658d3410d813b6fc6ceb654ce2aa8c2d3094c944dc59c2041da6227810e3","README.md":"e4134dbdd253028a5ec516bc966c0b0535b29916320b3f9f5d4a48cb227dcd87","README.tpl":"1666549ee42d21584d5d15eacc4dde880b1b497074549e1cbf984e6a658d5a8b","doc_index.html":"237e960e25521efab85cf689c555a21612d9205310d87f764309a3d2f3d8be65","src/lib.rs":"db5c09203d1734b291fd32f1a8f134776ebc8cb22696ff7cf108ebbb44753eee","src/list.rs":"caea64702b3dc3c92aac6a74a214d30868af3257e72d03ca31b4929bc7fc314f","src/loop_logic.rs":"dc6e06f1cd53257eb2db0cda7218bc62fb841d8d26b939d672ae3f66dc42940f","src/sources/channel.rs":"598c1b2cb5cb5269aacd61d4b7b34f7898ed211608a3a7c5b0f0b1f05ea60d93","src/sources/generic.rs":"70e2efd01381d3273d270bc125057c2940e61392c840b7d06d73c78a80b4f353","src/sources/mod.rs":"0e4ff41203913cf252a0f8860534d20169e715d88953a428d99c5a8b77fa6288","src/sources/signals.rs":"52bdbe405f08c8bcafc0c17a4a2afc8caec2f0e23b593889b3526b5389c6b5bd","src/sources/timer.rs":"b2876895a05ffe25b50f6005dd3deb0d189841dfb4984fd647368c27ec444a78","tests/signals.rs":"f99b2a569e336eedae741d2c05f18845499e0effcbdefbd29b9ef7fed9ac12fd"},"package":"7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160"} \ No newline at end of file diff --git a/third_party/cargo/vendor/calloop-0.4.4/BUILD.bazel b/third_party/cargo/vendor/calloop-0.4.4/BUILD.bazel deleted file mode 100644 index fdb5edc..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/BUILD.bazel +++ /dev/null @@ -1,67 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT" -]) - -# Generated Targets - -rust_library( - name = "calloop", - srcs = glob(["**/*.rs"]), - aliases = { - }, - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.4.4", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/mio-0.6.22:mio", - "//third_party/cargo/vendor/mio-extras-2.0.6:mio_extras", - ] + selects.with_or({ - # cfg(unix) - ( - "@io_bazel_rules_rust//rust/platform:x86_64-unknown-linux-gnu", - ): [ - "//third_party/cargo/vendor/nix-0.14.1:nix", - ], - "//conditions:default": [], - }), -) - -# Unsupported target "signals" with type "test" omitted diff --git a/third_party/cargo/vendor/calloop-0.4.4/CHANGELOG.md b/third_party/cargo/vendor/calloop-0.4.4/CHANGELOG.md deleted file mode 100644 index 3af6bf1..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/CHANGELOG.md +++ /dev/null @@ -1,69 +0,0 @@ -# Change Log - -## Unreleased - -## 0.4.4 -- 2019-06-13 - -- Update `nix` dependency to `0.14` - -## 0.4.3 -- 2019-02-17 - -- Update `mio` dependency -- Update `nix` dependency - -## 0.4.2 -- 2018-11-15 - -- Implement `Debug` for `InsertError`. - -## 0.4.1 -- 2018-11-14 - -- Disable the `sources::signal` module on FreeBSD so that the library can be built on this - platform. - -## 0.4.0 -- 2018-11-04 - -- **Breaking** Use `mio-extras` instead of `mio-more` which is not maintained. -- **Breaking** Reexport `mio` rather than selectively re-exporting some of its types. -- Add methods to `Generic` to retrive the inner `Rc` and construct it from an `Rc` -- **Breaking** `LoopHandle::insert_source` now allows to retrieve the source on error. - -## 0.3.2 -- 2018-09-25 - -- Fix the contents of `EventedRawFd` which was erroneously not public. - -## 0.3.1 -- 2018-09-25 - -- introduce `EventedRawFd` as a special case for the `Generic` event source, for when - you really have to manipulate raw fds -- Don't panic when the removal of an event source trigger the removal of an other one - -## 0.3.0 -- 2018-09-10 - -- Fixed a bug where inserting an event source from within a callback caused a panic. -- **[breaking]** Erase the `Data` type parameter from `Source` and `Idle`, for - improved ergonomics. - -## 0.2.2 -- 2018-09-10 - -- Introduce an `EventLoop::run` method, as well as the `LoopSignal` handle allowing to - wakeup or stop the event loop from anywhere. - -## 0.2.1 -- 2018-09-01 - -- Use `FnOnce` for insertion in idle callbacks. - -## 0.2.0 -- 2018-08-30 - -- **[breaking]** Add a `&mut shared_data` argument to `EventLoop::dispatch(..)` to share data - between callbacks. - -## 0.1.1 -- 2018-08-29 - -- `Generic` event source for wrapping arbitrary `Evented` types -- timer event sources -- UNIX signal event sources -- channel event sources - -## 0.1.0 -- 2018-08-24 - -Initial release diff --git a/third_party/cargo/vendor/calloop-0.4.4/Cargo.toml b/third_party/cargo/vendor/calloop-0.4.4/Cargo.toml deleted file mode 100644 index a7f1533..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "calloop" -version = "0.4.4" -authors = ["Victor Berger "] -autotests = false -description = "A callback-based event loop" -documentation = "https://docs.rs/calloop/" -keywords = ["events", "loop", "callback"] -license = "MIT" -repository = "https://github.com/Smithay/calloop" - -[[test]] -name = "signals" -harness = false -[dependencies.mio] -version = "0.6" - -[dependencies.mio-extras] -version = "2.0" -[dev-dependencies.lazycell] -version = "=1.0.0" -[target."cfg(unix)".dependencies.nix] -version = "0.14.1" -[badges.codecov] -repository = "Smithay/calloop" - -[badges.travis-ci] -repository = "Smithay/calloop" diff --git a/third_party/cargo/vendor/calloop-0.4.4/README.md b/third_party/cargo/vendor/calloop-0.4.4/README.md deleted file mode 100644 index 575e146..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/README.md +++ /dev/null @@ -1,86 +0,0 @@ -[![crates.io](http://meritbadge.herokuapp.com/calloop)](https://crates.io/crates/calloop) -[![docs.rs](https://docs.rs/calloop/badge.svg)](https://docs.rs/calloop) -[![Build Status](https://travis-ci.org/Smithay/calloop.svg?branch=master)](https://travis-ci.org/Smithay/calloop) -[![Coverage Status](https://codecov.io/gh/Smithay/calloop/branch/master/graph/badge.svg)](https://codecov.io/gh/Smithay/calloop) - -# calloop - -Calloop, a Callback-based Event Loop - -This crate provides an `EventLoop` type, which is a small abstraction -over an `mio`-based event loop. The main difference between this crate -and other traditional rust event loops is that it is based on callbacks: -you can register several event sources, each being associated with a callback -closure that will be invoked whenever the associated event source generates -events. - -This crate was initially an implementation detail of `wayland-server`, and has been -split-off for reuse. I expect it to be more useful for GUI programs or graphical -servers (like wayland-based apps) than performance critial networking code, which are -more versed towards `tokio` and async-await. It mostly shines in the conception of -modular infrastructures, allowing different modules to use the same event loop without -needing to know about each other. - -### How to use it - -```rust -extern crate calloop; - -use std::time::Duration; - -fn main() { - // Create the event loop - let mut event_loop = calloop::EventLoop::new().expect("Failed to initialize the event loop!"); - // Retrieve an handle. It is used to insert new sources into the event loop - // It can be cloned, allowing you to insert sources from within sources - let handle = event_loop.handle(); - - /* - * Setup your program, inserting event sources in the loop - */ - - // Actual run of your loop - loop { - // Dispatch received events to their callbacks, waiting at most 20 ms for - // new events - // - // The `&mut shared_data` is a mutable reference that will be forwarded to all - // your callbacks, allowing them to easily share some state - event_loop.dispatch(Some(Duration::from_millis(20)), &mut shared_data); - - /* - * Insert here the processing you need to do do between each event loop run - * like your drawing logic if you're doing a GUI app for example. - */ - } -} -``` - -### Event source types - -The event loop is backed by `mio`, as such anything implementing the `mio::Evented` trait -can be used as an event source, with some adapter code (see the `EventSource` trait). - -This crate also provide some adapters for common event sources such as: - -- MPSC channels -- Timers -- unix signals - -As well as generic `mio::Evented` objects. - -It is also possible to insert "idle" callbacks. These callbacks represent computations that -need to be done at some point, but are not as urgent as processing the events. These callbacks -are stored and then executed during `EventLoop::dispatch(..)`, once all events from the sources -have been processed. - -### Custom event sources - -You can create custom event sources can will be inserted in the event loop by -implementing the `EventSource` trait. This notably involves the creation of an -internal type implementing the `EventDispatcher` trait, that will convert -readiness notifications from `mio` into events generated by your sources. For example, -by reading the new messages from a display server socket and producing an event and -calling the user callback for each of them. - -License: MIT diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/lib.rs b/third_party/cargo/vendor/calloop-0.4.4/src/lib.rs deleted file mode 100644 index 42e4b4d..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/lib.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Calloop, a Callback-based Event Loop -//! -//! This crate provides an `EventLoop` type, which is a small abstraction -//! over an `mio`-based event loop. The main difference between this crate -//! and other traditional rust event loops is that it is based on callbacks: -//! you can register several event sources, each being associated with a callback -//! closure that will be invoked whenever the associated event source generates -//! events. -//! -//! This crate was initially an implementation detail of `wayland-server`, and has been -//! split-off for reuse. I expect it to be more useful for GUI programs or graphical -//! servers (like wayland-based apps) than performance critial networking code, which are -//! more versed towards `tokio` and async-await. It mostly shines in the conception of -//! modular infrastructures, allowing different modules to use the same event loop without -//! needing to know about each other. -//! -//! ## How to use it -//! -//! ```no_run -//! extern crate calloop; -//! -//! use std::time::Duration; -//! -//! fn main() { -//! // Create the event loop -//! let mut event_loop = calloop::EventLoop::new().expect("Failed to initialize the event loop!"); -//! // Retrieve an handle. It is used to insert new sources into the event loop -//! // It can be cloned, allowing you to insert sources from within sources -//! let handle = event_loop.handle(); -//! -//! /* -//! * Setup your program, inserting event sources in the loop -//! */ -//! -//! // Actual run of your loop -//! loop { -//! // Dispatch received events to their callbacks, waiting at most 20 ms for -//! // new events -//! // -//! // The `&mut shared_data` is a mutable reference that will be forwarded to all -//! // your callbacks, allowing them to easily share some state -//! # let mut shared_data = unimplemented!(); -//! event_loop.dispatch(Some(Duration::from_millis(20)), &mut shared_data); -//! -//! /* -//! * Insert here the processing you need to do do between each event loop run -//! * like your drawing logic if you're doing a GUI app for example. -//! */ -//! } -//! } -//! ``` -//! -//! ## Event source types -//! -//! The event loop is backed by `mio`, as such anything implementing the `mio::Evented` trait -//! can be used as an event source, with some adapter code (see the `EventSource` trait). -//! -//! This crate also provide some adapters for common event sources such as: -//! -//! - MPSC channels -//! - Timers -//! - unix signals -//! -//! As well as generic `mio::Evented` objects. -//! -//! It is also possible to insert "idle" callbacks. These callbacks represent computations that -//! need to be done at some point, but are not as urgent as processing the events. These callbacks -//! are stored and then executed during `EventLoop::dispatch(..)`, once all events from the sources -//! have been processed. -//! -//! ## Custom event sources -//! -//! You can create custom event sources can will be inserted in the event loop by -//! implementing the `EventSource` trait. This notably involves the creation of an -//! internal type implementing the `EventDispatcher` trait, that will convert -//! readiness notifications from `mio` into events generated by your sources. For example, -//! by reading the new messages from a display server socket and producing an event and -//! calling the user callback for each of them. - -#![warn(missing_docs)] - -pub extern crate mio; -extern crate mio_extras; -#[cfg(unix)] -extern crate nix; - -pub use self::loop_logic::{EventLoop, InsertError, LoopHandle, LoopSignal}; -pub use self::sources::*; - -mod list; -mod loop_logic; -mod sources; diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/list.rs b/third_party/cargo/vendor/calloop-0.4.4/src/list.rs deleted file mode 100644 index e9e1356..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/list.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::cell::RefCell; -use std::rc::Rc; - -use mio::Token; - -use sources::EventDispatcher; - -pub(crate) struct SourceList { - sources: Vec>>>>, -} - -impl SourceList { - pub(crate) fn new() -> SourceList { - SourceList { - sources: Vec::new(), - } - } - - pub(crate) fn get_dispatcher( - &self, - token: Token, - ) -> Option>>> { - match self.sources.get(token.0) { - Some(&Some(ref dispatcher)) => Some(dispatcher.clone()), - _ => None, - } - } - - pub(crate) fn add_source(&mut self, dispatcher: Rc>>) -> Token { - let free_id = self.sources.iter().position(Option::is_none); - if let Some(id) = free_id { - self.sources[id] = Some(dispatcher); - Token(id) - } else { - self.sources.push(Some(dispatcher)); - Token(self.sources.len() - 1) - } - } - - // this method returns the removed dispatcher to ensure it is not dropped - // while the refcell containing the list is borrowed, as dropping a dispatcher - // can trigger the removal of an other source - pub(crate) fn del_source( - &mut self, - token: Token, - ) -> Option>>> { - ::std::mem::replace(&mut self.sources[token.0], None) - } -} - -pub(crate) trait ErasedList { - // this returs a value for the same reason as above, but we must erase its type - // due to the `Data` parameter, hence Box - fn del_source(&mut self, token: Token) -> Box<::std::any::Any>; -} - -impl ErasedList for SourceList { - fn del_source(&mut self, token: Token) -> Box<::std::any::Any> { - Box::new(self.del_source(token)) - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/loop_logic.rs b/third_party/cargo/vendor/calloop-0.4.4/src/loop_logic.rs deleted file mode 100644 index 57850e1..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/loop_logic.rs +++ /dev/null @@ -1,335 +0,0 @@ -use std::cell::RefCell; -use std::fmt::{self, Debug, Formatter}; -use std::io; -use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; -use std::time::Duration; - -use mio::{Events, Poll, PollOpt, Ready, Registration, SetReadiness}; - -use list::SourceList; -use sources::{EventSource, Idle, Source}; - -/// An handle to an event loop -/// -/// This handle allows you to insert new sources and idles in this event loop, -/// it can be cloned, and it is possible to insert new sources from within a source -/// callback. -pub struct LoopHandle { - poll: Rc, - list: Rc>>, - idles: Rc>>>>>>, -} - -impl Clone for LoopHandle { - fn clone(&self) -> LoopHandle { - LoopHandle { - poll: self.poll.clone(), - list: self.list.clone(), - idles: self.idles.clone(), - } - } -} - -/// An error generated when trying to insert an event source -pub struct InsertError { - /// The source that could not be inserted - pub source: E, - /// The generated error - pub error: io::Error, -} - -impl Debug for InsertError { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { - write!(formatter, "{:?}", self.error) - } -} - -impl From> for io::Error { - fn from(e: InsertError) -> io::Error { - e.error - } -} - -impl LoopHandle { - /// Insert an new event source in the loop - /// - /// The provided callback will be called during the dispatching cycles whenever the - /// associated source generates events, see `EventLoop::dispatch(..)` for details. - pub fn insert_source( - &self, - source: E, - callback: F, - ) -> Result, InsertError> { - let dispatcher = source.make_dispatcher(callback); - - let token = self.list.borrow_mut().add_source(dispatcher); - - let interest = source.interest(); - let opt = source.pollopts(); - - if let Err(e) = self.poll.register(&source, token, interest, opt) { - return Err(InsertError { source, error: e }); - } - - Ok(Source { - source, - poll: self.poll.clone(), - list: self.list.clone(), - token, - }) - } - - /// Insert an idle callback - /// - /// This callback will be called during a dispatching cycle when the event loop has - /// finished processing all pending events from the sources and becomes idle. - pub fn insert_idle(&self, callback: F) -> Idle { - let mut opt_cb = Some(callback); - let callback = Rc::new(RefCell::new(Some(Box::new(move |data: &mut Data| { - if let Some(cb) = opt_cb.take() { - cb(data); - } - }) as Box))); - self.idles.borrow_mut().push(callback.clone()); - Idle { callback } - } -} - -/// An event loop -/// -/// This loop can host several event sources, that can be dynamically added or removed. -pub struct EventLoop { - handle: LoopHandle, - events_buffer: Events, - stop_signal: Arc, - wakeup: SetReadiness, -} - -impl EventLoop { - /// Create a new event loop - /// - /// It is backed by an `mio` provided machinnery, and will fail if the `mio` - /// initialization fails. - pub fn new() -> io::Result> { - let handle = LoopHandle { - poll: Rc::new(Poll::new()?), - list: Rc::new(RefCell::new(SourceList::new())), - idles: Rc::new(RefCell::new(Vec::new())), - }; - // create a wakeup event source - let (wakeup_registration, wakeup_readiness) = Registration::new2(); - let mut wakeup_source = ::sources::generic::Generic::new(wakeup_registration); - wakeup_source.set_interest(Ready::readable()); - wakeup_source.set_pollopts(PollOpt::edge()); - let readiness2 = wakeup_readiness.clone(); - handle.insert_source(wakeup_source, move |_, _| { - // unmark the readiness so that the wakeup source is not - // processed in a loop - readiness2.set_readiness(Ready::empty()).unwrap(); - })?; - Ok(EventLoop { - handle, - events_buffer: Events::with_capacity(32), - stop_signal: Arc::new(AtomicBool::new(false)), - wakeup: wakeup_readiness, - }) - } - - /// Retrieve a loop handle - pub fn handle(&self) -> LoopHandle { - self.handle.clone() - } - - fn dispatch_events(&mut self, timeout: Option, data: &mut Data) -> io::Result<()> { - self.events_buffer.clear(); - self.handle.poll.poll(&mut self.events_buffer, timeout)?; - - loop { - if self.events_buffer.is_empty() { - break; - } - - for event in &self.events_buffer { - let opt_dispatcher = self.handle.list.borrow().get_dispatcher(event.token()); - if let Some(dispatcher) = opt_dispatcher { - dispatcher.borrow_mut().ready(event.readiness(), data); - } - } - - // process remaining events if any - self.events_buffer.clear(); - self.handle - .poll - .poll(&mut self.events_buffer, Some(Duration::from_millis(0)))?; - } - - Ok(()) - } - - fn dispatch_idles(&mut self, data: &mut Data) { - let idles = ::std::mem::replace(&mut *self.handle.idles.borrow_mut(), Vec::new()); - for idle in idles { - if let Some(ref mut callback) = *idle.borrow_mut() { - callback(data); - } - } - } - - /// Dispatch pending events to their callbacks - /// - /// Some source have events available, their callbacks will be immediatly called. - /// Otherwise this will wait until an event is receive or the provided `timeout` - /// is reached. If `timeout` is `None`, it will wait without a duration limit. - /// - /// Once pending events have been processed or the timeout is reached, all pending - /// idle callbacks will be fired before this method returns. - pub fn dispatch(&mut self, timeout: Option, data: &mut Data) -> io::Result<()> { - self.dispatch_events(timeout, data)?; - - self.dispatch_idles(data); - - Ok(()) - } - - /// Get a signal to stop this event loop from running - /// - /// To be used in conjunction with the `run()` method. - pub fn get_signal(&self) -> LoopSignal { - LoopSignal { - signal: self.stop_signal.clone(), - wakeup: self.wakeup.clone(), - } - } - - /// Run this event loop - /// - /// This will repeatedly try to dispatch events (see the `dispatch()` method) on - /// this event loop, waiting at most `timeout` every time. - /// - /// Between each dispatch wait, your provided callback will be called. - /// - /// You can use the `get_signal()` method to retrieve a way to stop or wakeup - /// the event loop from anywhere. - pub fn run( - &mut self, - timeout: Option, - data: &mut Data, - mut cb: F, - ) -> io::Result<()> - where - F: FnMut(&mut Data), - { - self.stop_signal.store(false, Ordering::Release); - while !self.stop_signal.load(Ordering::Acquire) { - self.dispatch(timeout, data)?; - cb(data); - } - Ok(()) - } -} - -/// A signal that can be shared between thread to stop or wakeup a running -/// event loop -#[derive(Clone)] -pub struct LoopSignal { - signal: Arc, - wakeup: SetReadiness, -} - -impl LoopSignal { - /// Stop the event loop - /// - /// Once this method is called, the next time the event loop has finished - /// waiting for events, it will return rather than starting to wait again. - /// - /// This is only usefull if you are using the `EventLoop::run()` method. - pub fn stop(&self) { - self.signal.store(true, Ordering::Release); - } - - /// Wake up the event loop - /// - /// This sends a dummy event to the event loop to simulate the reception - /// of an event, making the wait return early. Called after `stop()`, this - /// ensures the event loop will terminate quickly if you specified a long - /// timeout (or no timeout at all) to the `dispatch` or `run` method. - pub fn wakeup(&self) { - self.wakeup.set_readiness(Ready::readable()).unwrap(); - } -} - -#[cfg(test)] -mod tests { - use std::time::Duration; - - use super::EventLoop; - - #[test] - fn dispatch_idle() { - let mut event_loop = EventLoop::new().unwrap(); - - let mut dispatched = false; - - event_loop.handle().insert_idle(|d| { - *d = true; - }); - - event_loop - .dispatch(Some(Duration::from_millis(0)), &mut dispatched) - .unwrap(); - - assert!(dispatched); - } - - #[test] - fn cancel_idle() { - let mut event_loop = EventLoop::new().unwrap(); - - let mut dispatched = false; - - let idle = event_loop.handle().insert_idle(move |d| { - *d = true; - }); - - idle.cancel(); - - event_loop - .dispatch(Some(Duration::from_millis(0)), &mut dispatched) - .unwrap(); - - assert!(!dispatched); - } - - #[test] - fn wakeup() { - let mut event_loop = EventLoop::new().unwrap(); - - let signal = event_loop.get_signal(); - - ::std::thread::spawn(move || { - ::std::thread::sleep(Duration::from_millis(500)); - signal.wakeup(); - }); - - // the test should return - event_loop.dispatch(None, &mut ()).unwrap(); - } - - #[test] - fn wakeup_stop() { - let mut event_loop = EventLoop::new().unwrap(); - - let signal = event_loop.get_signal(); - - ::std::thread::spawn(move || { - ::std::thread::sleep(Duration::from_millis(500)); - signal.stop(); - signal.wakeup(); - }); - - // the test should return - event_loop.run(None, &mut (), |_| {}).unwrap(); - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/sources/channel.rs b/third_party/cargo/vendor/calloop-0.4.4/src/sources/channel.rs deleted file mode 100644 index 7c72270..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/sources/channel.rs +++ /dev/null @@ -1,183 +0,0 @@ -//! An MPSC channel whose receiving end is an event source -//! -//! Create a channel using `Channel::::new()`, which returns a -//! `Sender` that can be cloned and sent accross threads if `T: Send`, -//! and a `Channel` that can be inserted into an `EventLoop`. It will generate -//! one event per message. -//! -//! This implementation is based on -//! [`mio_more::channel`](https://docs.rs/mio-more/*/mio_more/channel/index.html). - -use std::cell::RefCell; -use std::io; -use std::rc::Rc; -use std::sync::mpsc::TryRecvError; - -use mio::{Evented, Poll, PollOpt, Ready, Token}; - -use mio_extras::channel::{self as miochan, Receiver}; -pub use mio_extras::channel::{SendError, Sender, SyncSender, TrySendError}; - -use {EventDispatcher, EventSource}; - -/// The events generated by the channel event source -pub enum Event { - /// A message was received and is bundled here - Msg(T), - /// The channel was closed - /// - /// This means all the `Sender`s associated with this channel - /// have been dropped, no more messages will ever be received. - Closed, -} - -/// The receiving end of the channel -/// -/// This is the event source to be inserted into your `EventLoop`. -pub struct Channel { - receiver: Rc>, -} - -/// Create a new asynchronous channel -pub fn channel() -> (Sender, Channel) { - let (sender, receiver) = miochan::channel(); - ( - sender, - Channel { - receiver: Rc::new(receiver), - }, - ) -} - -/// Create a new synchronous, bounded channel -pub fn sync_channel(bound: usize) -> (SyncSender, Channel) { - let (sender, receiver) = miochan::sync_channel(bound); - ( - sender, - Channel { - receiver: Rc::new(receiver), - }, - ) -} - -impl Evented for Channel { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - self.receiver.register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - self.receiver.reregister(poll, token, interest, opts) - } - - fn deregister(&self, poll: &Poll) -> io::Result<()> { - self.receiver.deregister(poll) - } -} - -impl EventSource for Channel { - type Event = Event; - - fn interest(&self) -> Ready { - Ready::readable() - } - - fn pollopts(&self) -> PollOpt { - PollOpt::edge() - } - - fn make_dispatcher, &mut Data) + 'static>( - &self, - callback: F, - ) -> Rc>> { - Rc::new(RefCell::new(Dispatcher { - _data: ::std::marker::PhantomData, - receiver: self.receiver.clone(), - callback, - })) - } -} - -struct Dispatcher, &mut Data)> { - _data: ::std::marker::PhantomData, - receiver: Rc>, - callback: F, -} - -impl, &mut Data)> EventDispatcher for Dispatcher { - fn ready(&mut self, _: Ready, data: &mut Data) { - loop { - match self.receiver.try_recv() { - Ok(val) => (self.callback)(Event::Msg(val), data), - Err(TryRecvError::Empty) => break, - Err(TryRecvError::Disconnected) => { - (self.callback)(Event::Closed, data); - break; - } - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn basic_channel() { - let mut event_loop = ::EventLoop::new().unwrap(); - - let handle = event_loop.handle(); - - let (tx, rx) = channel::<()>(); - - // (got_msg, got_closed) - let mut got = (false, false); - - let _source = handle - .insert_source(rx, move |evt, got: &mut (bool, bool)| match evt { - Event::Msg(()) => { - got.0 = true; - } - Event::Closed => { - got.1 = true; - } - }) - .map_err(Into::::into) - .unwrap(); - - // nothing is sent, nothing is received - event_loop - .dispatch(Some(::std::time::Duration::from_millis(0)), &mut got) - .unwrap(); - - assert_eq!(got, (false, false)); - - // a message is send - tx.send(()).unwrap(); - event_loop - .dispatch(Some(::std::time::Duration::from_millis(0)), &mut got) - .unwrap(); - - assert_eq!(got, (true, false)); - - // the sender is dropped - ::std::mem::drop(tx); - event_loop - .dispatch(Some(::std::time::Duration::from_millis(0)), &mut got) - .unwrap(); - - assert_eq!(got, (true, true)); - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/sources/generic.rs b/third_party/cargo/vendor/calloop-0.4.4/src/sources/generic.rs deleted file mode 100644 index dc70471..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/sources/generic.rs +++ /dev/null @@ -1,301 +0,0 @@ -//! A generic event source wrapping an `Evented` type - -use std::cell::RefCell; -use std::io; -#[cfg(unix)] -use std::os::unix::io::{AsRawFd, RawFd}; -use std::rc::Rc; - -use mio::{Evented, Poll, PollOpt, Ready, Token}; - -use {EventDispatcher, EventSource}; - -/// A generic event source wrapping an `Evented` type -/// -/// It will simply forward the readiness and an acces to -/// the wrapped `Evented` type to the suer callback. See -/// the `Event` type in this module. -pub struct Generic { - inner: Rc>, - interest: Ready, - pollopts: PollOpt, -} - -impl Generic { - /// Wrap an `Evented` type into a `Generic` event source - /// - /// It is initialized with no interest nor poll options, - /// as such you should set them using the `set_interest` - /// and `set_pollopts` methods before inserting it in the - /// event loop. - pub fn new(source: E) -> Generic { - Generic { - inner: Rc::new(RefCell::new(source)), - interest: Ready::empty(), - pollopts: PollOpt::empty(), - } - } - - /// Wrap an `Evented` type from an `Rc` into a `Generic` event source - /// - /// Same as the `new` method, but you can provide a source that is alreay - /// in a reference counted pointer, so that `Generic` won't add a new - /// layer. This is useful if you need to share this source accross multiple - /// modules, and `calloop` is not the first one to be initialized. - pub fn from_rc(source: Rc>) -> Generic { - Generic { - inner: source, - interest: Ready::empty(), - pollopts: PollOpt::empty(), - } - } - - /// Change the interest for this evented source - /// - /// If the source was already inserted in an event loop, - /// it needs to be re-registered for the change to take - /// effect. - pub fn set_interest(&mut self, interest: Ready) { - self.interest = interest; - } - - /// Change the poll options for this evented source - /// - /// If the source was already inserted in an event loop, - /// it needs to be re-registered for the change to take - /// effect. - pub fn set_pollopts(&mut self, pollopts: PollOpt) { - self.pollopts = pollopts; - } - - /// Get a clone of the inner `Rc` wrapping your event source - pub fn clone_inner(&self) -> Rc> { - self.inner.clone() - } - - /// Unwrap the `Generic` source to retrieve the underlying `Evented`. - /// - /// If you didn't clone the `Rc>` from the `Event` you received, - /// the returned `Rc` should be unique. - pub fn unwrap(self) -> Rc> { - self.inner - } -} - -impl Generic> { - /// Wrap a file descriptor based source into a `Generic` event source. - /// - /// This will only work with poll-compatible file descriptors, which typically - /// not include basic files. - #[cfg(unix)] - pub fn from_fd_source(source: Fd) -> Generic> { - Generic::new(EventedFd(source)) - } -} - -impl Generic { - /// Wrap a raw file descriptor into a `Generic` event source. - /// - /// This will only work with poll-compatible file descriptors, which typically - /// not include basic files. - /// - /// This does _not_ take ownership of the file descriptor, hence you are responsible - /// of its correct lifetime. - #[cfg(unix)] - pub fn from_raw_fd(fd: RawFd) -> Generic { - Generic::new(EventedRawFd(fd)) - } -} - -/// An event generated by the `Generic` source -pub struct Event { - /// An access to the source that generated this event - pub source: Rc>, - /// The associated rediness - pub readiness: Ready, -} - -/// An owning wrapper implementing Evented for any file descriptor based type in Unix -#[cfg(unix)] -pub struct EventedFd(pub F); - -impl Evented for EventedFd { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - ::mio::unix::EventedFd(&self.0.as_raw_fd()).register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - ::mio::unix::EventedFd(&self.0.as_raw_fd()).reregister(poll, token, interest, opts) - } - - fn deregister(&self, poll: &Poll) -> io::Result<()> { - ::mio::unix::EventedFd(&self.0.as_raw_fd()).deregister(poll) - } -} - -/// A wrapper implementing Evented for any raw file descriptor. -/// -/// It does _not_ take ownership of the file descriptor, you are -/// responsible for ensuring its correct lifetime. -#[cfg(unix)] -pub struct EventedRawFd(pub RawFd); - -impl Evented for EventedRawFd { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - ::mio::unix::EventedFd(&self.0).register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - ::mio::unix::EventedFd(&self.0).reregister(poll, token, interest, opts) - } - - fn deregister(&self, poll: &Poll) -> io::Result<()> { - ::mio::unix::EventedFd(&self.0).deregister(poll) - } -} - -impl Evented for Generic { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - self.inner.borrow().register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - self.inner.borrow().reregister(poll, token, interest, opts) - } - - fn deregister(&self, poll: &Poll) -> io::Result<()> { - self.inner.borrow().deregister(poll) - } -} - -impl EventSource for Generic { - type Event = Event; - - fn interest(&self) -> Ready { - self.interest - } - - fn pollopts(&self) -> PollOpt { - self.pollopts - } - - fn make_dispatcher, &mut Data) + 'static>( - &self, - callback: F, - ) -> Rc>> { - Rc::new(RefCell::new(Dispatcher { - _data: ::std::marker::PhantomData, - inner: self.inner.clone(), - callback, - })) - } -} - -struct Dispatcher, &mut Data)> { - _data: ::std::marker::PhantomData, - inner: Rc>, - callback: F, -} - -impl, &mut Data)> EventDispatcher - for Dispatcher -{ - fn ready(&mut self, ready: Ready, data: &mut Data) { - (self.callback)( - Event { - source: self.inner.clone(), - readiness: ready, - }, - data, - ) - } -} - -#[cfg(test)] -mod test { - use std::io::{self, Read, Write}; - - use super::{Event, Generic}; - #[cfg(unix)] - #[test] - fn dispatch_unix() { - use std::os::unix::net::UnixStream; - - let mut event_loop = ::EventLoop::new().unwrap(); - - let handle = event_loop.handle(); - - let (mut tx, rx) = UnixStream::pair().unwrap(); - - let mut generic = Generic::from_fd_source(rx); - generic.set_interest(::mio::Ready::readable()); - - let mut dispached = false; - - handle - .insert_source(generic, move |Event { source, readiness }, d| { - assert!(readiness.is_readable()); - // we have not registered for writability - assert!(!readiness.is_writable()); - let mut buffer = vec![0; 10]; - let ret = source.borrow_mut().0.read(&mut buffer).unwrap(); - assert_eq!(ret, 6); - assert_eq!(&buffer[..6], &[1, 2, 3, 4, 5, 6]); - - *d = true; - }) - .map_err(Into::::into) - .unwrap(); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) - .unwrap(); - - assert!(!dispached); - - tx.write(&[1, 2, 3, 4, 5, 6]).unwrap(); - tx.flush().unwrap(); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) - .unwrap(); - - assert!(dispached); - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/sources/mod.rs b/third_party/cargo/vendor/calloop-0.4.4/src/sources/mod.rs deleted file mode 100644 index 68e40ba..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/sources/mod.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::cell::RefCell; -use std::io; -use std::rc::Rc; - -use mio::{Evented, Poll, PollOpt, Ready, Token}; - -use list::ErasedList; - -pub mod channel; -pub mod generic; -#[cfg(target_os = "linux")] -pub mod signals; -pub mod timer; - -/// Trait representing a source that can be inserted into an EventLoop -/// -/// This is the interface between the source and the loop, you need to -/// implement it to use your custom event sources. -pub trait EventSource: Evented { - /// The type of events generated by your sources - type Event; - - /// The interest value that will be given to `mio` when registering your source - fn interest(&self) -> Ready; - - /// The pollopt value that will be given to `mio` when registering your source - fn pollopts(&self) -> PollOpt; - - /// Wrap an user callback into a dispatcher, that will convert an `mio` readiness - /// into an event - fn make_dispatcher( - &self, - callback: F, - ) -> Rc>>; -} - -/// An event dispatcher -/// -/// It is the junction between user callbacks and and an event source, -/// receiving `mio` readinesses, converting them into appropriate events -/// and calling their inner user callback. -pub trait EventDispatcher { - /// The source has a readiness event - fn ready(&mut self, ready: Ready, data: &mut Data); -} - -/// An event source that has been inserted into the event loop -/// -/// This handle allows you to remove it, and possibly more interactions -/// depending on the source kind that will be provided by the `Deref` -/// implementation of this struct to the evented object. -/// -/// Dropping this handle does not deregister this source from the event loop, -/// but will drop the wrapped `EventSource`, maybe rendering it inert depending on -/// its implementation. -pub struct Source { - pub(crate) source: E, - pub(crate) poll: Rc, - pub(crate) list: Rc>, - pub(crate) token: Token, -} - -impl Source { - /// Refresh the registration of this event source to the loop - /// - /// This can be necessary if the evented object provides methods to change - /// its behavior. Its documentation should inform you of the need for re-registration. - pub fn reregister(&self) -> io::Result<()> { - self.poll.reregister( - &self.source, - self.token, - self.source.interest(), - self.source.pollopts(), - ) - } - - /// Remove this source from the event loop - /// - /// You are given the evented object back. - pub fn remove(self) -> E { - let _ = self.poll.deregister(&self.source); - let _dispatcher = self.list.borrow_mut().del_source(self.token); - self.source - } -} - -impl ::std::ops::Deref for Source { - type Target = E; - fn deref(&self) -> &E { - &self.source - } -} - -impl ::std::ops::DerefMut for Source { - fn deref_mut(&mut self) -> &mut E { - &mut self.source - } -} - -/// An idle callback that was inserted in this loop -/// -/// This handle allows you to cancel the callback. Dropping -/// it will *not* cancel it. -pub struct Idle { - pub(crate) callback: Rc>, -} - -impl Idle { - /// Cancel the idle callback if it was not already run - pub fn cancel(self) { - self.callback.borrow_mut().cancel(); - } -} - -pub(crate) trait ErasedIdle { - fn cancel(&mut self); -} - -impl ErasedIdle for Option> { - fn cancel(&mut self) { - self.take(); - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/sources/signals.rs b/third_party/cargo/vendor/calloop-0.4.4/src/sources/signals.rs deleted file mode 100644 index 299940d..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/sources/signals.rs +++ /dev/null @@ -1,217 +0,0 @@ -//! Event source for tracking Unix signals -//! -//! Only available on `#[cfg(unix)]`. -//! -//! This allows you to track and receive Unix signals through the event loop -//! rather than by registering signal handlers. It uses `signalfd` under the hood. -//! -//! The source will take care of masking and unmasking signals for the thread it runs on, -//! but you are responsible for masking them on other threads if you run them. The simplest -//! way to ensure that is to setup the signal event source before spawning any thread, as -//! they'll inherit their parent signal mask. - -use std::cell::RefCell; -use std::io; -use std::os::raw::c_int; -use std::os::unix::io::AsRawFd; -use std::rc::Rc; - -use mio::{Evented, Poll, PollOpt, Ready, Token}; - -use nix::sys::signal::SigSet; -pub use nix::sys::signal::Signal; -pub use nix::sys::signalfd::siginfo; -use nix::sys::signalfd::{SfdFlags, SignalFd}; - -use {EventDispatcher, EventSource}; - -/// An event generated by the signal event source -#[derive(Copy, Clone)] -pub struct Event { - info: siginfo, -} - -impl Event { - /// Retrieve the signal number that was receive - pub fn signal(&self) -> Signal { - Signal::from_c_int(self.info.ssi_signo as c_int).unwrap() - } - - /// Access the full `siginfo_t` associated with this signal event - pub fn full_info(&self) -> siginfo { - self.info - } -} - -/// An event source for receiving Unix signals -pub struct Signals { - sfd: Rc>, - mask: SigSet, -} - -impl Signals { - /// Create a new signal event source listening on the specified list of signals - pub fn new(signals: &[Signal]) -> io::Result { - let mut mask = SigSet::empty(); - for &s in signals { - mask.add(s); - } - - // Mask the signals for this thread - mask.thread_block().map_err(no_nix_err)?; - // Create the SignalFd - let sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK | SfdFlags::SFD_CLOEXEC) - .map_err(no_nix_err)?; - - Ok(Signals { - sfd: Rc::new(RefCell::new(sfd)), - mask, - }) - } - - /// Add a list of signals to the signals source - /// - /// If this function returns an error, the signal mask of the thread may - /// have still been changed. - pub fn add_signals(&mut self, signals: &[Signal]) -> io::Result<()> { - for &s in signals { - self.mask.add(s); - } - self.mask.thread_block().map_err(no_nix_err)?; - self.sfd - .borrow_mut() - .set_mask(&self.mask) - .map_err(no_nix_err)?; - Ok(()) - } - - /// Remove a list of signals to the signals source - /// - /// If this function returns an error, the signal mask of the thread may - /// have still been changed. - pub fn remove_signals(&mut self, signals: &[Signal]) -> io::Result<()> { - let mut removed = SigSet::empty(); - for &s in signals { - self.mask.remove(s); - removed.add(s); - } - removed.thread_unblock().map_err(no_nix_err)?; - self.sfd - .borrow_mut() - .set_mask(&self.mask) - .map_err(no_nix_err)?; - Ok(()) - } - - /// Replace the list of signals of the source - /// - /// If this function returns an error, the signal mask of the thread may - /// have still been changed. - pub fn set_signals(&mut self, signals: &[Signal]) -> io::Result<()> { - let mut new_mask = SigSet::empty(); - for &s in signals { - new_mask.add(s); - } - - self.mask.thread_unblock().map_err(no_nix_err)?; - new_mask.thread_block().map_err(no_nix_err)?; - self.sfd - .borrow_mut() - .set_mask(&new_mask) - .map_err(no_nix_err)?; - self.mask = new_mask; - - Ok(()) - } -} - -impl Drop for Signals { - fn drop(&mut self) { - // we cannot handle error here - if let Err(e) = self.mask.thread_unblock() { - eprintln!("[calloop] Failed to unmask signals: {:?}", e); - } - } -} - -fn no_nix_err(err: ::nix::Error) -> io::Error { - match err { - ::nix::Error::Sys(errno) => errno.into(), - _ => unreachable!(), - } -} - -impl Evented for Signals { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - ::mio::unix::EventedFd(&self.sfd.borrow().as_raw_fd()).register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - ::mio::unix::EventedFd(&self.sfd.borrow().as_raw_fd()) - .reregister(poll, token, interest, opts) - } - - fn deregister(&self, poll: &Poll) -> io::Result<()> { - ::mio::unix::EventedFd(&self.sfd.borrow().as_raw_fd()).deregister(poll) - } -} - -impl EventSource for Signals { - type Event = Event; - - fn interest(&self) -> Ready { - Ready::readable() - } - - fn pollopts(&self) -> PollOpt { - PollOpt::edge() - } - - fn make_dispatcher( - &self, - callback: F, - ) -> Rc>> { - Rc::new(RefCell::new(Dispatcher { - _data: ::std::marker::PhantomData, - callback, - sfd: self.sfd.clone(), - })) - } -} - -struct Dispatcher { - _data: ::std::marker::PhantomData, - callback: F, - sfd: Rc>, -} - -impl EventDispatcher for Dispatcher { - fn ready(&mut self, _: Ready, data: &mut Data) { - loop { - let ret = self.sfd.borrow_mut().read_signal(); - match ret { - Ok(Some(info)) => (self.callback)(Event { info }, data), - Ok(None) => { - // nothing more to read - break; - } - Err(e) => { - eprintln!("[calloop] Error reading from signalfd: {:?}", e); - break; - } - } - } - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/src/sources/timer.rs b/third_party/cargo/vendor/calloop-0.4.4/src/sources/timer.rs deleted file mode 100644 index 57ff43e..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/src/sources/timer.rs +++ /dev/null @@ -1,311 +0,0 @@ -//! Timer-based event sources -//! -//! A `Timer` is a general time-tracking object. It is used by setting timeouts, -//! and generates events whenever a timeout expires. -//! -//! The `Timer` event source provides an handle `TimerHandle`, which is used -//! to set or cancel timeouts. This handle is cloneable and can be send accross threads -//! if `T: Send`, allowing you to setup timeouts from any point of your program. -//! -//! This implementation is based on -//! [`mio_more::timer`](https://docs.rs/mio-more/*/mio_more/timer/index.html). - -use std::cell::RefCell; -use std::io; -use std::rc::Rc; -use std::sync::{Arc, Mutex}; -use std::time::Duration; - -use mio::{Evented, Poll, PollOpt, Ready, Token}; - -use mio_extras::timer as mio_timer; - -pub use self::mio_timer::Timeout; - -use {EventDispatcher, EventSource}; - -/// A Timer event source -/// -/// It generates events of type `(T, TimerHandle)`, providing you -/// an handle inside the event callback, allowing you to set new timeouts -/// as a response to a timeout being reached (for reccuring ticks for example). -pub struct Timer { - inner: Arc>>, -} - -impl Timer { - /// Create a new timer with default parameters - /// - /// Default time resolution is 100ms - pub fn new() -> Timer { - Timer { - inner: Arc::new(Mutex::new(mio_timer::Builder::default().build())), - } - } - - /// Create a new timer with a specific time resolution - pub fn with_resolution(resolution: Duration) -> Timer { - Timer { - inner: Arc::new(Mutex::new( - mio_timer::Builder::default() - .tick_duration(resolution) - .build(), - )), - } - } - - /// Get an handle for this timer - pub fn handle(&self) -> TimerHandle { - TimerHandle { - inner: self.inner.clone(), - } - } -} - -/// An handle to a timer, used to set or cancel timeouts -/// -/// This handle can be cloned, and can be sent accross thread as long -/// as `T: Send`. -pub struct TimerHandle { - inner: Arc>>, -} - -// Manual impl of `Clone` as #[derive(Clone)] adds a `T: Clone` bound -impl Clone for TimerHandle { - fn clone(&self) -> TimerHandle { - TimerHandle { - inner: self.inner.clone(), - } - } -} - -impl TimerHandle { - /// Set a new timeout - /// - /// The associated `data` will be given as argument to the callback. - /// - /// The returned `Timeout` can be used to cancel it. You can drop it if you don't - /// plan to cancel this timeout. - /// - /// This method can fail if the timer already has too many pending timeouts, currently - /// capacity is `2^16`. - pub fn add_timeout(&self, delay_from_now: Duration, data: T) -> Timeout { - self.inner.lock().unwrap().set_timeout(delay_from_now, data) - } - - /// Cancel a previsouly set timeout and retrieve the associated data - /// - /// This method returns `None` if the timeout does not exist (it has already fired - /// or has already been cancelled). - pub fn cancel_timeout(&self, timeout: &Timeout) -> Option { - self.inner.lock().unwrap().cancel_timeout(timeout) - } -} - -impl Evented for Timer { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - self.inner - .lock() - .unwrap() - .register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> io::Result<()> { - self.inner - .lock() - .unwrap() - .reregister(poll, token, interest, opts) - } - - fn deregister(&self, poll: &Poll) -> io::Result<()> { - self.inner.lock().unwrap().deregister(poll) - } -} - -impl EventSource for Timer { - type Event = (T, TimerHandle); - - fn interest(&self) -> Ready { - Ready::readable() - } - - fn pollopts(&self) -> PollOpt { - PollOpt::edge() - } - - fn make_dispatcher), &mut Data) + 'static>( - &self, - callback: F, - ) -> Rc>> { - Rc::new(RefCell::new(Dispatcher { - _data: ::std::marker::PhantomData, - timer: self.inner.clone(), - callback, - })) - } -} - -struct Dispatcher), &mut Data)> { - _data: ::std::marker::PhantomData, - timer: Arc>>, - callback: F, -} - -impl), &mut Data)> EventDispatcher - for Dispatcher -{ - fn ready(&mut self, _: Ready, data: &mut Data) { - let handle = TimerHandle { - inner: self.timer.clone(), - }; - loop { - let opt_evt = self.timer.lock().unwrap().poll(); - match opt_evt { - Some(val) => (self.callback)((val, handle.clone()), data), - None => break, - } - } - } -} - -#[cfg(test)] -mod tests { - use std::io; - use std::time::Duration; - - use super::*; - - #[test] - fn single_timer() { - let mut event_loop = ::EventLoop::new().unwrap(); - - let evl_handle = event_loop.handle(); - - let mut fired = false; - - let timer = evl_handle - .insert_source(Timer::<()>::new(), move |((), _), f| { - *f = true; - }) - .map_err(Into::::into) - .unwrap(); - - timer.handle().add_timeout(Duration::from_millis(300), ()); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(100)), &mut fired) - .unwrap(); - - // it should not have fired yet - assert!(!fired); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired) - .unwrap(); - - // it should have fired now - assert!(fired); - } - - #[test] - fn multi_timout_order() { - let mut event_loop = ::EventLoop::new().unwrap(); - - let evl_handle = event_loop.handle(); - - let mut fired = Vec::new(); - - let timer = evl_handle - .insert_source(Timer::new(), |(val, _), fired: &mut Vec| { - fired.push(val); - }) - .map_err(Into::::into) - .unwrap(); - - timer.handle().add_timeout(Duration::from_millis(300), 1); - timer.handle().add_timeout(Duration::from_millis(100), 2); - timer.handle().add_timeout(Duration::from_millis(600), 3); - - // 3 dispatches as each returns once at least one event occured - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(200)), &mut fired) - .unwrap(); - - assert_eq!(&fired, &[2]); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired) - .unwrap(); - - assert_eq!(&fired, &[2, 1]); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(400)), &mut fired) - .unwrap(); - - assert_eq!(&fired, &[2, 1, 3]); - } - - #[test] - fn timer_cancel() { - let mut event_loop = ::EventLoop::new().unwrap(); - - let evl_handle = event_loop.handle(); - - let mut fired = Vec::new(); - - let timer = evl_handle - .insert_source(Timer::new(), |(val, _), fired: &mut Vec| { - fired.push(val) - }) - .map_err(Into::::into) - .unwrap(); - - let timeout1 = timer.handle().add_timeout(Duration::from_millis(300), 1); - let timeout2 = timer.handle().add_timeout(Duration::from_millis(100), 2); - let timeout3 = timer.handle().add_timeout(Duration::from_millis(600), 3); - - // 3 dispatches as each returns once at least one event occured - // - // The timeouts 1 and 3 and not cancelled right away, but still before they - // fire - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(200)), &mut fired) - .unwrap(); - - assert_eq!(&fired, &[2]); - - // timeout2 has already fired, we cancel timeout1 - assert_eq!(timer.handle().cancel_timeout(&timeout2), None); - assert_eq!(timer.handle().cancel_timeout(&timeout1), Some(1)); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired) - .unwrap(); - - assert_eq!(&fired, &[2]); - - // cancel timeout3 - assert_eq!(timer.handle().cancel_timeout(&timeout3), Some(3)); - - event_loop - .dispatch(Some(::std::time::Duration::from_millis(600)), &mut fired) - .unwrap(); - - assert_eq!(&fired, &[2]); - } -} diff --git a/third_party/cargo/vendor/calloop-0.4.4/tests/signals.rs b/third_party/cargo/vendor/calloop-0.4.4/tests/signals.rs deleted file mode 100644 index 5a1c19c..0000000 --- a/third_party/cargo/vendor/calloop-0.4.4/tests/signals.rs +++ /dev/null @@ -1,134 +0,0 @@ -// These tests cannot run as a regular test because cargo would spawn a thread to run it, -// failing the signal masking. So we make our own, non-threaded harnessing - -#[cfg(unix)] -fn main() { - for test in self::test::TESTS { - test(); - // reset the signal mask between tests - self::test::reset_mask(); - } -} - -#[cfg(not(unix))] -fn main() {} - -#[cfg(unix)] -mod test { - extern crate calloop; - extern crate nix; - - use std::io; - use std::time::Duration; - - use self::calloop::signals::{Signal, Signals}; - use self::calloop::EventLoop; - - use self::nix::sys::signal::{kill, SigSet}; - use self::nix::unistd::Pid; - - pub const TESTS: &'static [fn()] = &[single_usr1, usr2_added_afterwards, usr2_signal_removed]; - - pub fn reset_mask() { - SigSet::empty().thread_set_mask().unwrap(); - } - - fn single_usr1() { - let mut event_loop = EventLoop::new().unwrap(); - - let mut signal_received = false; - - let _signal_source = event_loop - .handle() - .insert_source( - Signals::new(&[Signal::SIGUSR1]).unwrap(), - move |evt, rcv| { - assert!(evt.signal() == Signal::SIGUSR1); - *rcv = true; - }, - ) - .map_err(Into::::into) - .unwrap(); - - // send ourselves a SIGUSR1 - kill(Pid::this(), Signal::SIGUSR1).unwrap(); - - event_loop - .dispatch(Some(Duration::from_millis(10)), &mut signal_received) - .unwrap(); - - assert!(signal_received); - } - - fn usr2_added_afterwards() { - let mut event_loop = EventLoop::new().unwrap(); - - let mut signal_received = None; - - let mut signal_source = event_loop - .handle() - .insert_source( - Signals::new(&[Signal::SIGUSR1]).unwrap(), - move |evt, rcv| { - *rcv = Some(evt.signal()); - }, - ) - .map_err(Into::::into) - .unwrap(); - - signal_source.add_signals(&[Signal::SIGUSR2]).unwrap(); - - // send ourselves a SIGUSR2 - kill(Pid::this(), Signal::SIGUSR2).unwrap(); - - event_loop - .dispatch(Some(Duration::from_millis(10)), &mut signal_received) - .unwrap(); - - assert_eq!(signal_received, Some(Signal::SIGUSR2)); - } - - fn usr2_signal_removed() { - let mut event_loop = EventLoop::new().unwrap(); - - let mut signal_received = None; - - let mut signal_source = event_loop - .handle() - .insert_source( - Signals::new(&[Signal::SIGUSR1, Signal::SIGUSR2]).unwrap(), - move |evt, rcv| { - *rcv = Some(evt.signal()); - }, - ) - .map_err(Into::::into) - .unwrap(); - - signal_source.remove_signals(&[Signal::SIGUSR2]).unwrap(); - - // block sigusr2 anyway, to not be killed by it - let mut set = SigSet::empty(); - set.add(Signal::SIGUSR2); - set.thread_block().unwrap(); - - // send ourselves a SIGUSR2 - kill(Pid::this(), Signal::SIGUSR2).unwrap(); - - event_loop - .dispatch(Some(Duration::from_millis(10)), &mut signal_received) - .unwrap(); - - // we should not have received anything, as we don't listen to SIGUSR2 any more - assert!(signal_received.is_none()); - - // swap the signals from [SIGUSR1] to [SIGUSR2] - signal_source.set_signals(&[Signal::SIGUSR2]).unwrap(); - - event_loop - .dispatch(Some(Duration::from_millis(10)), &mut signal_received) - .unwrap(); - - // we should get back the pending SIGUSR2 now - assert_eq!(signal_received, Some(Signal::SIGUSR2)); - } -} diff --git a/third_party/cargo/vendor/calloop-0.6.5/.cargo-checksum.json b/third_party/cargo/vendor/calloop-0.6.5/.cargo-checksum.json new file mode 100644 index 0000000..fd8bfd2 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"c916cc970702495b51b88ea50a6273dbf63df8af9d04b428a81ee6f529d6dee2","Cargo.toml":"384e2b55aac8f774018ed2eb86b77c32317e69c7027de41319c14662ea12b232","LICENSE.txt":"4b71658d3410d813b6fc6ceb654ce2aa8c2d3094c944dc59c2041da6227810e3","README.md":"74cfe8fb4dbdcc369fa26a24a37ade177ef48e6518c8b009eedfd8af2227acc1","README.tpl":"1666549ee42d21584d5d15eacc4dde880b1b497074549e1cbf984e6a658d5a8b","doc_index.html":"237e960e25521efab85cf689c555a21612d9205310d87f764309a3d2f3d8be65","src/lib.rs":"481766731101a22f6bc5c6487aa66ded14367a07ce713acb07a7bfff888fd146","src/list.rs":"05474939e31bb99ed55e9e81dadfed934df65523a8ce146af3ed020d275f0d5f","src/loop_logic.rs":"e7e6c555672de6b71db2d9ebf154269051f4c5c034b69b4c0884f919138083f1","src/sources/channel.rs":"adaee1067851158974951a27d88b72dd2499a39f8e0d0da25d26d84dfb928a62","src/sources/generic.rs":"3eff90e2da6a33cf09210931c097ee95f4cb57a42ac57a23bb41f7e40b01e4a8","src/sources/mod.rs":"414e19397cdc172f5eec19007767a5fb228eef4c6e67a40e4ffd1c868f96174c","src/sources/ping.rs":"65012317e2ea19ed59c6eefd4dff4ab51b8f6c13fcd843f092b70399728bd0e6","src/sources/signals.rs":"9ebd97f23baafa096ed29fd3d2260f89c1e77099f16fb1782e9bed7030c4aa4d","src/sources/timer.rs":"1540c93d67a9024812e2baf2ea496c96261a74bd83c6a2996bf43dfd35eccfc7","src/sys/epoll.rs":"bf349e558dac71acf121a9344dc14a9a04969328bf844e475c139a515051d953","src/sys/kqueue.rs":"56da414bda3dbff971874f714350118d9a7048e37975e44af2cd21322060f092","src/sys/mod.rs":"58922662f8ec89b27b0dacfc7f3fe3bd9ece81a085940a35d194091ddf2832fd","tests/signals.rs":"cd76a1f56a5922781289da3d07d88ec80f9439b2faa3ccc9bad1091005251dce"},"package":"0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c"} \ No newline at end of file diff --git a/third_party/cargo/vendor/calloop-0.6.5/BUILD.bazel b/third_party/cargo/vendor/calloop-0.6.5/BUILD.bazel new file mode 100644 index 0000000..1e74556 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/BUILD.bazel @@ -0,0 +1,57 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT" +]) + +# Generated Targets + +rust_library( + name = "calloop", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.6.5", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/log-0.4.11:log", + "//third_party/cargo/vendor/nix-0.18.0:nix", + ], +) + +# Unsupported target "signals" with type "test" omitted diff --git a/third_party/cargo/vendor/calloop-0.6.5/CHANGELOG.md b/third_party/cargo/vendor/calloop-0.6.5/CHANGELOG.md new file mode 100644 index 0000000..6c61ced --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/CHANGELOG.md @@ -0,0 +1,130 @@ +# Change Log + +## Unreleased + +## 0.6.5 -- 2020-10-07 + +#### Fixes + +- Channel now signals readinnes after the event has actually been sent, fixing a race + condition where the event loop would try to read the message before it has been + written. + +## 0.6.4 -- 2020-08-30 + +#### Fixes + +- Fix double borrow during dispatch when some event source is getting removed + +## 0.6.3 -- 2020-08-27 + +#### Aditions + +- Add support for `openbsd`, `netbsd`, and `dragonfly`. +- `InsertError` now implements `std::error::Error`. + +#### Changes + +- Allow non-`'static` dispatch `Data`. `Data` is passed as an argument to the + `callback`s while dispatching. This change allows defining `Data` types which + can hold references to other values. +- `dispatch` now will retry on `EINTR`. + +## 0.6.2 -- 2020-04-23 + +- Update the README and keywords for crates.io + +## 0.6.1 -- 2020-04-22 + +- Introduce `LoopHandle::kill` to allow dropping a source from within its callback + +## 0.6.0 -- 2020-04-22 + +- Drop the `mio` dependency +- **Breaking Change**: Significantly rework the `calloop` API, notably: + - Event sources are now owned by the `EventLoop` + - Users can now again set the polling mode (Level/Edge/OneShot) +- Introduce the `Ping` event source + +## 0.5.2 -- 2020-04-14 + +- `channel::Channel` is now `Send`, allowing you to create a channel in one thread and sending + its receiving end to an other thread for event loop insertion. + +## 0.5.1 -- 2020-03-14 + +- Update `mio` to `0.7` + +## 0.5.0 -- 2020-02-07 + +- Update to 2018 edition +- Update `nix` dependency to `0.17` +- **Breaking** Update `mio` dependency to `0.7.0-alpha.1`. The API of `calloop` for custom + event sources significantly changed, and the channel and timer event sources are now + implemented in `calloop` rather than pulled from `mio-extras`. + +## 0.4.4 -- 2019-06-13 + +- Update `nix` dependency to `0.14` + +## 0.4.3 -- 2019-02-17 + +- Update `mio` dependency +- Update `nix` dependency + +## 0.4.2 -- 2018-11-15 + +- Implement `Debug` for `InsertError`. + +## 0.4.1 -- 2018-11-14 + +- Disable the `sources::signal` module on FreeBSD so that the library can be built on this + platform. + +## 0.4.0 -- 2018-11-04 + +- **Breaking** Use `mio-extras` instead of `mio-more` which is not maintained. +- **Breaking** Reexport `mio` rather than selectively re-exporting some of its types. +- Add methods to `Generic` to retrive the inner `Rc` and construct it from an `Rc` +- **Breaking** `LoopHandle::insert_source` now allows to retrieve the source on error. + +## 0.3.2 -- 2018-09-25 + +- Fix the contents of `EventedRawFd` which was erroneously not public. + +## 0.3.1 -- 2018-09-25 + +- introduce `EventedRawFd` as a special case for the `Generic` event source, for when + you really have to manipulate raw fds +- Don't panic when the removal of an event source trigger the removal of an other one + +## 0.3.0 -- 2018-09-10 + +- Fixed a bug where inserting an event source from within a callback caused a panic. +- **[breaking]** Erase the `Data` type parameter from `Source` and `Idle`, for + improved ergonomics. + +## 0.2.2 -- 2018-09-10 + +- Introduce an `EventLoop::run` method, as well as the `LoopSignal` handle allowing to + wakeup or stop the event loop from anywhere. + +## 0.2.1 -- 2018-09-01 + +- Use `FnOnce` for insertion in idle callbacks. + +## 0.2.0 -- 2018-08-30 + +- **[breaking]** Add a `&mut shared_data` argument to `EventLoop::dispatch(..)` to share data + between callbacks. + +## 0.1.1 -- 2018-08-29 + +- `Generic` event source for wrapping arbitrary `Evented` types +- timer event sources +- UNIX signal event sources +- channel event sources + +## 0.1.0 -- 2018-08-24 + +Initial release diff --git a/third_party/cargo/vendor/calloop-0.6.5/Cargo.toml b/third_party/cargo/vendor/calloop-0.6.5/Cargo.toml new file mode 100644 index 0000000..a951ef7 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "calloop" +version = "0.6.5" +authors = ["Victor Berger "] +autotests = false +description = "A callback-based event loop" +documentation = "https://docs.rs/calloop/" +readme = "README.md" +keywords = ["events", "loop", "callback", "eventloop", "unix"] +license = "MIT" +repository = "https://github.com/Smithay/calloop" + +[[test]] +name = "signals" +harness = false +[dependencies.log] +version = "0.4" + +[dependencies.nix] +version = "0.18" +[badges.codecov] +repository = "Smithay/calloop" diff --git a/third_party/cargo/vendor/calloop-0.4.4/LICENSE.txt b/third_party/cargo/vendor/calloop-0.6.5/LICENSE.txt similarity index 100% rename from third_party/cargo/vendor/calloop-0.4.4/LICENSE.txt rename to third_party/cargo/vendor/calloop-0.6.5/LICENSE.txt diff --git a/third_party/cargo/vendor/calloop-0.6.5/README.md b/third_party/cargo/vendor/calloop-0.6.5/README.md new file mode 100644 index 0000000..cc3df48 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/README.md @@ -0,0 +1,79 @@ +[![crates.io](http://meritbadge.herokuapp.com/calloop)](https://crates.io/crates/calloop) +[![docs.rs](https://docs.rs/calloop/badge.svg)](https://docs.rs/calloop) +[![Continuous Integration](https://github.com/Smithay/calloop/workflows/Continuous%20Integration/badge.svg)](https://github.com/Smithay/calloop/actions?query=workflow%3A%22Continuous+Integration%22) +[![Coverage Status](https://codecov.io/gh/Smithay/calloop/branch/master/graph/badge.svg)](https://codecov.io/gh/Smithay/calloop) + +# calloop + +Calloop, a Callback-based Event Loop + +This crate provides an `EventLoop` type, which is a small abstraction +over epoll or kaqueue for unix systems. The main difference between this crate +and other traditional rust event loops is that it is based on callbacks: +you can register several event sources, each being associated with a callback +closure that will be invoked whenever the associated event source generates +events. + +This crate was initially an implementation detail of `wayland-server`, and has been +split-off for reuse. I expect it to be more useful for GUI programs or graphical +servers (like wayland-based apps) than performance critial networking code, which are +more versed towards `tokio` and async-await. It mostly shines in the conception of +modular infrastructures, allowing different modules to use the same event loop without +needing to know about each other. + +### How to use it + +```rust +extern crate calloop; + +use std::time::Duration; + +fn main() { + // Create the event loop + let mut event_loop = calloop::EventLoop::new().expect("Failed to initialize the event loop!"); + // Retrieve an handle. It is used to insert new sources into the event loop + // It can be cloned, allowing you to insert sources from within sources + let handle = event_loop.handle(); + + /* + * Setup your program, inserting event sources in the loop + */ + + // Actual run of your loop + loop { + // Dispatch received events to their callbacks, waiting at most 20 ms for + // new events + // + // The `&mut shared_data` is a mutable reference that will be forwarded to all + // your callbacks, allowing them to easily share some state + event_loop.dispatch(Some(Duration::from_millis(20)), &mut shared_data); + + /* + * Insert here the processing you need to do do between each event loop run + * like your drawing logic if you're doing a GUI app for example. + */ + } +} +``` + +### Event source types + +This crate provides some adapters for common event sources such as: + +- MPSC channels +- Timers +- unix signals + +As well as generic handler for monitoring file desriptors. + +It is also possible to insert "idle" callbacks. These callbacks represent computations that +need to be done at some point, but are not as urgent as processing the events. These callbacks +are stored and then executed during `EventLoop::dispatch(..)`, once all events from the sources +have been processed. + +### Custom event sources + +You can create custom event sources that can inserted in the event loop by +implementing the `EventSource` trait. + +License: MIT diff --git a/third_party/cargo/vendor/calloop-0.4.4/README.tpl b/third_party/cargo/vendor/calloop-0.6.5/README.tpl similarity index 100% rename from third_party/cargo/vendor/calloop-0.4.4/README.tpl rename to third_party/cargo/vendor/calloop-0.6.5/README.tpl diff --git a/third_party/cargo/vendor/calloop-0.4.4/doc_index.html b/third_party/cargo/vendor/calloop-0.6.5/doc_index.html similarity index 100% rename from third_party/cargo/vendor/calloop-0.4.4/doc_index.html rename to third_party/cargo/vendor/calloop-0.6.5/doc_index.html diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/lib.rs b/third_party/cargo/vendor/calloop-0.6.5/src/lib.rs new file mode 100644 index 0000000..76d7f10 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/lib.rs @@ -0,0 +1,98 @@ +//! Calloop, a Callback-based Event Loop +//! +//! This crate provides an `EventLoop` type, which is a small abstraction +//! over a polling system. The main difference between this crate +//! and other traditional rust event loops is that it is based on callbacks: +//! you can register several event sources, each being associated with a callback +//! closure that will be invoked whenever the associated event source generates +//! events. +//! +//! This crate was initially an implementation detail of `wayland-server`, and has been +//! split-off for reuse. I expect it to be more useful for GUI programs or graphical +//! servers (like wayland-based apps) than performance critial networking code, which are +//! more versed towards `tokio` and async-await. It mostly shines in the conception of +//! modular infrastructures, allowing different modules to use the same event loop without +//! needing to know about each other. +//! +//! ## How to use it +//! +//! ``` +//! extern crate calloop; +//! +//! use std::time::Duration; +//! +//! fn main() { +//! // Create the event loop +//! let mut event_loop = calloop::EventLoop::new().expect("Failed to initialize the event loop!"); +//! // Retrieve an handle. It is used to insert new sources into the event loop +//! // It can be cloned, allowing you to insert sources from within sources +//! let handle = event_loop.handle(); +//! +//! /* +//! * Setup your program, inserting event sources in the loop +//! */ +//! +//! // Actual run of your loop +//! loop { +//! // Dispatch received events to their callbacks, waiting at most 20 ms for +//! // new events +//! // +//! // The `&mut shared_data` is a mutable reference that will be forwarded to all +//! // your callbacks, allowing them to easily share some state +//! # let mut shared_data = (); +//! event_loop.dispatch(Duration::from_millis(20), &mut shared_data); +//! +//! /* +//! * Insert here the processing you need to do do between each event loop run +//! * like your drawing logic if you're doing a GUI app for example. +//! */ +//! +//! # break; +//! } +//! } +//! ``` +//! +//! ## Event source types +//! +//! The event loop is backed by an OS provided polling selector (epoll on Linux). +//! +//! This crate also provide some adapters for common event sources such as: +//! +//! - MPSC channels +//! - Timers +//! - unix signals +//! +//! As well as generic objects backed by file descriptors. +//! +//! It is also possible to insert "idle" callbacks. These callbacks represent computations that +//! need to be done at some point, but are not as urgent as processing the events. These callbacks +//! are stored and then executed during `EventLoop::dispatch(..)`, once all events from the sources +//! have been processed. +//! +//! ## Custom event sources +//! +//! You can create custom event sources can will be inserted in the event loop by +//! implementing the `EventSource` trait. This can be done either directly from the file +//! descriptors of your source of interest, or by wrapping an other event source and further +//! processing its events. An `EventSource` can register more than one file descriptor and +//! aggregate them. + +#![warn(missing_docs)] + +mod sys; + +pub use sys::{Interest, Mode, Poll, Readiness, Token}; + +pub use self::loop_logic::{EventLoop, InsertError, LoopHandle, LoopSignal}; +pub use self::sources::*; + +mod list; +mod loop_logic; +mod sources; + +fn no_nix_err(err: nix::Error) -> std::io::Error { + match err { + ::nix::Error::Sys(errno) => errno.into(), + _ => unreachable!(), + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/list.rs b/third_party/cargo/vendor/calloop-0.6.5/src/list.rs new file mode 100644 index 0000000..1196e6a --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/list.rs @@ -0,0 +1,55 @@ +use std::rc::Rc; + +use crate::Token; + +use crate::sources::EventDispatcher; + +pub(crate) struct SourceList { + sources: Vec>>>, +} + +impl SourceList { + pub(crate) fn new() -> SourceList { + SourceList { + sources: Vec::new(), + } + } + + pub(crate) fn contains(&self, token: Token) -> bool { + self.sources + .get(token.id as usize) + .map(Option::is_some) + .unwrap_or(false) + } + + pub(crate) fn get_dispatcher(&self, token: Token) -> Option>> { + match self.sources.get(token.id as usize) { + Some(&Some(ref dispatcher)) => Some(dispatcher.clone()), + _ => None, + } + } + + pub(crate) fn add_source(&mut self, dispatcher: Rc>) -> Token { + let free_id = self.sources.iter().position(Option::is_none); + if let Some(id) = free_id { + self.sources[id] = Some(dispatcher); + Token { + id: id as u32, + sub_id: 0, + } + } else { + self.sources.push(Some(dispatcher)); + Token { + id: (self.sources.len() - 1) as u32, + sub_id: 0, + } + } + } + + // this method returns the removed dispatcher to ensure it is not dropped + // while the refcell containing the list is borrowed, as dropping a dispatcher + // can trigger the removal of an other source + pub(crate) fn del_source(&mut self, token: Token) -> Option>> { + ::std::mem::replace(&mut self.sources[token.id as usize], None) + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/loop_logic.rs b/third_party/cargo/vendor/calloop-0.6.5/src/loop_logic.rs new file mode 100644 index 0000000..96b3c5d --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/loop_logic.rs @@ -0,0 +1,852 @@ +use std::cell::RefCell; +use std::fmt::{self, Debug, Formatter}; +use std::io; +use std::rc::Rc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::time::Duration; + +use crate::list::SourceList; +use crate::sources::{EventSource, Idle, IdleDispatcher, Source}; +use crate::Poll; + +type IdleCallback = Rc>>; + +struct LoopInner { + poll: RefCell, + sources: RefCell>, + idles: RefCell>>, +} + +/// An handle to an event loop +/// +/// This handle allows you to insert new sources and idles in this event loop, +/// it can be cloned, and it is possible to insert new sources from within a source +/// callback. +pub struct LoopHandle { + inner: Rc>, +} + +#[cfg(not(tarpaulin_include))] +impl Clone for LoopHandle { + fn clone(&self) -> LoopHandle { + LoopHandle { + inner: self.inner.clone(), + } + } +} + +/// An error generated when trying to insert an event source +pub struct InsertError { + /// The source that could not be inserted + pub source: E, + /// The generated error + pub error: io::Error, +} + +#[cfg(not(tarpaulin_include))] +impl Debug for InsertError { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { + write!(formatter, "{:?}", self.error) + } +} + +#[cfg(not(tarpaulin_include))] +impl std::fmt::Display for InsertError { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { + write!(formatter, "{}", self.error) + } +} + +#[cfg(not(tarpaulin_include))] +impl From> for io::Error { + fn from(e: InsertError) -> io::Error { + e.error + } +} + +#[cfg(not(tarpaulin_include))] +impl std::error::Error for InsertError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.error.source() + } +} + +impl LoopHandle { + /// Insert an new event source in the loop + /// + /// The provided callback will be called during the dispatching cycles whenever the + /// associated source generates events, see `EventLoop::dispatch(..)` for details. + pub fn insert_source(&self, source: S, callback: F) -> Result, InsertError> + where + S: EventSource + 'static, + F: FnMut(S::Event, &mut S::Metadata, &mut Data) -> S::Ret + 'static, + { + let mut sources = self.inner.sources.borrow_mut(); + let mut poll = self.inner.poll.borrow_mut(); + + let dispatcher = Rc::new(RefCell::new(crate::sources::Dispatcher::::new( + source, callback, + ))); + let token = sources.add_source(dispatcher); + + let ret = sources + .get_dispatcher(token) + .unwrap() + .register(&mut *poll, token); + + if let Err(error) = ret { + let source = sources + .del_source(token) + .expect("Source was just inserted?!") + .into_source_any() + .downcast::() + .map(|s| *s) + .unwrap_or_else(|_| panic!("Downcasting failed!")); + return Err(InsertError { error, source }); + } + + Ok(Source { + token, + _type: std::marker::PhantomData, + }) + } + + /// Insert an idle callback + /// + /// This callback will be called during a dispatching cycle when the event loop has + /// finished processing all pending events from the sources and becomes idle. + pub fn insert_idle(&self, callback: F) -> Idle { + let mut opt_cb = Some(callback); + let callback = Rc::new(RefCell::new(Some(move |data: &mut Data| { + if let Some(cb) = opt_cb.take() { + cb(data); + } + }))); + self.inner.idles.borrow_mut().push(callback.clone()); + Idle { callback } + } + + /// Access this event source + /// + /// This allows you to modify the event source without removing it from the event + /// loop if it allows it. + /// + /// Note that replacing it with an other using `mem::replace` or equivalent would not + /// correctly update its registration and generate errors. Instead you should remove + /// the source using the `remove()` method and then insert a new one. + /// + /// **Note**: This cannot be done from within the callback of the same source. + pub fn with_source T>( + &self, + source: &Source, + f: F, + ) -> T { + let disp = self + .inner + .sources + .borrow() + .get_dispatcher(source.token) + .expect("Attempting to access a non-existent source?!"); + let mut source_any = disp.as_source_any(); + let source_mut = source_any.downcast_mut::().expect("Downcasting failed!"); + f(source_mut) + } + + /// Enable this previously disabled event source + /// + /// This previously disabled source will start generating events again. + /// + /// **Note**: This cannot be done from within the callback of the same source. + pub fn enable(&self, source: &Source) -> io::Result<()> { + self.inner + .sources + .borrow() + .get_dispatcher(source.token) + .expect("Attempting to access a non-existent source?!") + .register(&mut *self.inner.poll.borrow_mut(), source.token) + } + + /// Make this source update its registration + /// + /// If after accessing the source you changed its parameters in a way that requires + /// updating its registration. + /// + /// **Note**: This cannot be done from within the callback of the same source. + pub fn update(&self, source: &Source) -> io::Result<()> { + self.inner + .sources + .borrow() + .get_dispatcher(source.token) + .expect("Attempting to access a non-existent source?!") + .reregister(&mut *self.inner.poll.borrow_mut(), source.token) + } + + /// Disable this event source + /// + /// The source remains in the event loop, but it'll no longer generate events + /// + /// **Note**: This cannot be done from within the callback of the same source. + pub fn disable(&self, source: &Source) -> io::Result<()> { + self.inner + .sources + .borrow() + .get_dispatcher(source.token) + .expect("Attempting to access a non-existent source?!") + .unregister(&mut *self.inner.poll.borrow_mut()) + } + + /// Remove this source from the event loop + /// + /// You are givent the `EventSource` back. + /// + /// **Note**: This cannot be done from within the callback of the same source. + pub fn remove(&self, source: Source) -> S { + let source = self + .inner + .sources + .borrow_mut() + .del_source(source.token) + .expect("Attempting to remove a non-existent source?!"); + if let Err(e) = source.unregister(&mut *self.inner.poll.borrow_mut()) { + log::warn!( + "[calloop] Failed to unregister source from the polling system: {:?}", + e + ); + } + source + .into_source_any() + .downcast::() + .map(|s| *s) + .unwrap_or_else(|_| panic!("Downcasting failed!")) + } + + /// Remove this event source from the event loop and drop it + /// + /// The source is not given back to you but instead dropped + /// + /// **Note**: This *can* be done from within the callback of the same source + pub fn kill(&self, source: Source) { + self.inner.sources.borrow_mut().del_source(source.token); + } +} + +/// An event loop +/// +/// This loop can host several event sources, that can be dynamically added or removed. +pub struct EventLoop { + handle: LoopHandle, + stop_signal: Arc, + ping: crate::sources::ping::Ping, +} + +impl EventLoop { + /// Create a new event loop + /// + /// Fails if the initialization of the polling system failed. + pub fn new() -> io::Result> { + let poll = Poll::new()?; + let handle = LoopHandle { + inner: Rc::new(LoopInner { + poll: RefCell::new(poll), + sources: RefCell::new(SourceList::new()), + idles: RefCell::new(Vec::new()), + }), + }; + let (ping, ping_source) = crate::sources::ping::make_ping()?; + handle.insert_source(ping_source, |_, _, _| {})?; + Ok(EventLoop { + handle, + stop_signal: Arc::new(AtomicBool::new(false)), + ping, + }) + } + + /// Retrieve a loop handle + pub fn handle(&self) -> LoopHandle { + self.handle.clone() + } + + fn dispatch_events( + &mut self, + mut timeout: Option, + data: &mut Data, + ) -> io::Result<()> { + let events = { + let mut poll = self.handle.inner.poll.borrow_mut(); + loop { + let now = std::time::Instant::now(); + let result = poll.poll(timeout); + + match result { + Ok(events) => break events, + Err(ref err) if err.kind() == io::ErrorKind::Interrupted => { + // Interrupted by a signal. Update timeout and retry. + if let Some(to) = timeout { + let elapsed = now.elapsed(); + if elapsed >= to { + return Ok(()); + } else { + timeout = Some(to - elapsed); + } + } + } + Err(err) => return Err(err), + }; + } + }; + + for event in events { + let opt_disp = self + .handle + .inner + .sources + .borrow() + .get_dispatcher(event.token); + + if let Some(disp) = opt_disp { + disp.process_events(event.readiness, event.token, data)?; + + if !self.handle.inner.sources.borrow().contains(event.token) { + // the source has been removed from within its callback, unregister it + let mut poll = self.handle.inner.poll.borrow_mut(); + if let Err(e) = disp.unregister(&mut *poll) { + log::warn!( + "[calloop] Failed to unregister source from the polling system: {:?}", + e + ); + } + } + } else { + log::warn!( + "[calloop] Received an event for non-existence source: {}", + event.token.id + ); + } + } + + Ok(()) + } + + fn dispatch_idles(&mut self, data: &mut Data) { + let idles = ::std::mem::replace(&mut *self.handle.inner.idles.borrow_mut(), Vec::new()); + for idle in idles { + idle.borrow_mut().dispatch(data); + } + } + + /// Dispatch pending events to their callbacks + /// + /// Some source have events available, their callbacks will be immediatly called. + /// Otherwise this will wait until an event is receive or the provided `timeout` + /// is reached. If `timeout` is `None`, it will wait without a duration limit. + /// + /// Once pending events have been processed or the timeout is reached, all pending + /// idle callbacks will be fired before this method returns. + pub fn dispatch>>( + &mut self, + timeout: D, + data: &mut Data, + ) -> io::Result<()> { + self.dispatch_events(timeout.into(), data)?; + + self.dispatch_idles(data); + + Ok(()) + } + + /// Get a signal to stop this event loop from running + /// + /// To be used in conjunction with the `run()` method. + pub fn get_signal(&self) -> LoopSignal { + LoopSignal { + signal: self.stop_signal.clone(), + ping: self.ping.clone(), + } + } + + /// Run this event loop + /// + /// This will repeatedly try to dispatch events (see the `dispatch()` method) on + /// this event loop, waiting at most `timeout` every time. + /// + /// Between each dispatch wait, your provided callback will be called. + /// + /// You can use the `get_signal()` method to retrieve a way to stop or wakeup + /// the event loop from anywhere. + pub fn run( + &mut self, + timeout: Option, + data: &mut Data, + mut cb: F, + ) -> io::Result<()> + where + F: FnMut(&mut Data), + { + self.stop_signal.store(false, Ordering::Release); + while !self.stop_signal.load(Ordering::Acquire) { + self.dispatch(timeout, data)?; + cb(data); + } + Ok(()) + } +} + +/// A signal that can be shared between thread to stop or wakeup a running +/// event loop +#[derive(Clone)] +pub struct LoopSignal { + signal: Arc, + ping: crate::sources::ping::Ping, +} + +impl LoopSignal { + /// Stop the event loop + /// + /// Once this method is called, the next time the event loop has finished + /// waiting for events, it will return rather than starting to wait again. + /// + /// This is only usefull if you are using the `EventLoop::run()` method. + pub fn stop(&self) { + self.signal.store(true, Ordering::Release); + } + + /// Wake up the event loop + /// + /// This sends a dummy event to the event loop to simulate the reception + /// of an event, making the wait return early. Called after `stop()`, this + /// ensures the event loop will terminate quickly if you specified a long + /// timeout (or no timeout at all) to the `dispatch` or `run` method. + pub fn wakeup(&self) { + self.ping.ping(); + } +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use crate::{ + generic::Generic, sources::ping::*, Interest, Mode, Poll, Readiness, Source, Token, + }; + + use super::EventLoop; + + #[test] + fn dispatch_idle() { + let mut event_loop = EventLoop::new().unwrap(); + + let mut dispatched = false; + + event_loop.handle().insert_idle(|d| { + *d = true; + }); + + event_loop + .dispatch(Some(Duration::from_millis(0)), &mut dispatched) + .unwrap(); + + assert!(dispatched); + } + + #[test] + fn cancel_idle() { + let mut event_loop = EventLoop::new().unwrap(); + + let mut dispatched = false; + + let idle = event_loop.handle().insert_idle(move |d| { + *d = true; + }); + + idle.cancel(); + + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + + assert!(!dispatched); + } + + #[test] + fn wakeup() { + let mut event_loop = EventLoop::new().unwrap(); + + let signal = event_loop.get_signal(); + + ::std::thread::spawn(move || { + ::std::thread::sleep(Duration::from_millis(500)); + signal.wakeup(); + }); + + // the test should return + event_loop.dispatch(None, &mut ()).unwrap(); + } + + #[test] + fn wakeup_stop() { + let mut event_loop = EventLoop::new().unwrap(); + + let signal = event_loop.get_signal(); + + ::std::thread::spawn(move || { + ::std::thread::sleep(Duration::from_millis(500)); + signal.stop(); + signal.wakeup(); + }); + + // the test should return + event_loop.run(None, &mut (), |_| {}).unwrap(); + } + + #[test] + fn insert_remove() { + let mut event_loop = EventLoop::<()>::new().unwrap(); + let source_1 = event_loop + .handle() + .insert_source(DummySource, |_, _, _| {}) + .unwrap(); + assert_eq!(source_1.token.id, 1); // numer 0 is the internal ping + let source_2 = event_loop + .handle() + .insert_source(DummySource, |_, _, _| {}) + .unwrap(); + assert_eq!(source_2.token.id, 2); + // ensure token reuse on source removal + event_loop.handle().remove(source_1); + + event_loop + .dispatch(Duration::from_millis(0), &mut ()) + .unwrap(); + + let source_3 = event_loop + .handle() + .insert_source(DummySource, |_, _, _| {}) + .unwrap(); + assert_eq!(source_3.token.id, 1); + } + + #[test] + fn insert_bad_source() { + let event_loop = EventLoop::<()>::new().unwrap(); + let ret = event_loop.handle().insert_source( + crate::sources::generic::Generic::from_fd(42, Interest::Readable, Mode::Level), + |_, _, _| Ok(()), + ); + assert!(ret.is_err()); + } + + #[test] + fn disarm_rearm() { + let mut event_loop = EventLoop::::new().unwrap(); + let (ping, ping_source) = make_ping().unwrap(); + + let ping_source = event_loop + .handle() + .insert_source(ping_source, |(), &mut (), dispatched| { + *dispatched = true; + }) + .unwrap(); + + ping.ping(); + let mut dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert_eq!(dispatched, true); + + // disable the source + ping.ping(); + event_loop.handle().disable(&ping_source).unwrap(); + let mut dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert_eq!(dispatched, false); + + // disabling it again is an error + event_loop.handle().disable(&ping_source).unwrap_err(); + + // reenable it, the previous ping now gets dispatched + event_loop.handle().enable(&ping_source).unwrap(); + let mut dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert_eq!(dispatched, true); + } + + #[test] + fn multiple_tokens() { + struct DoubleSource { + ping1: PingSource, + ping2: PingSource, + } + + impl crate::EventSource for DoubleSource { + type Event = u32; + type Metadata = (); + type Ret = (); + + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + mut callback: F, + ) -> std::io::Result<()> + where + F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + if token.sub_id == 1 { + self.ping1 + .process_events(readiness, token, |(), &mut ()| callback(1, &mut ())) + } else if token.sub_id == 2 { + self.ping2 + .process_events(readiness, token, |(), &mut ()| callback(2, &mut ())) + } else { + Ok(()) + } + } + + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.ping1.register(poll, Token { sub_id: 1, ..token })?; + self.ping2.register(poll, Token { sub_id: 2, ..token })?; + Ok(()) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.ping1.reregister(poll, Token { sub_id: 1, ..token })?; + self.ping2.reregister(poll, Token { sub_id: 2, ..token })?; + Ok(()) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + self.ping1.unregister(poll)?; + self.ping2.unregister(poll)?; + Ok(()) + } + } + + let mut event_loop = EventLoop::::new().unwrap(); + + let (ping1, source1) = make_ping().unwrap(); + let (ping2, source2) = make_ping().unwrap(); + + let source = DoubleSource { + ping1: source1, + ping2: source2, + }; + + event_loop + .handle() + .insert_source(source, |i, _, d| { + eprintln!("Dispatching {}", i); + *d += i + }) + .unwrap(); + + let mut dispatched = 0; + ping1.ping(); + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert_eq!(dispatched, 1); + + dispatched = 0; + ping2.ping(); + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert_eq!(dispatched, 2); + + dispatched = 0; + ping1.ping(); + ping2.ping(); + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert_eq!(dispatched, 3); + } + + #[test] + fn change_interests() { + use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType}; + use nix::unistd::{read, write}; + let mut event_loop = EventLoop::::new().unwrap(); + + let (sock1, sock2) = socketpair( + AddressFamily::Unix, + SockType::Stream, + None, + SockFlag::SOCK_NONBLOCK, + ) + .unwrap(); + + let source = Generic::from_fd(sock1, Interest::Readable, Mode::Level); + + let sock1 = event_loop + .handle() + .insert_source(source, |_, fd, dispatched| { + *dispatched = true; + // read all contents available to drain the socket + let mut buf = [0u8; 32]; + loop { + match read(fd.0, &mut buf) { + Ok(0) => break, // closed pipe, we are now inert + Ok(_) => {} + Err(e) => { + let e = crate::no_nix_err(e); + if e.kind() == std::io::ErrorKind::WouldBlock { + break; + // nothing more to read + } else { + // propagate error + return Err(e); + } + } + } + } + Ok(()) + }) + .unwrap(); + + // first dispatch, nothing is readable + let mut dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(!dispatched); + + // write something, the socket becomes readable + write(sock2, &[1, 2, 3]).unwrap(); + dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(dispatched); + + // All has been read, no longer readable + dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(!dispatched); + + // change the interests for writability instead + event_loop + .handle() + .with_source(&sock1, |g| g.interest = Interest::Writable); + event_loop.handle().update(&sock1).unwrap(); + + // the socket is writable + dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(dispatched); + + // change back to readable + event_loop + .handle() + .with_source(&sock1, |g| g.interest = Interest::Readable); + event_loop.handle().update(&sock1).unwrap(); + + // the socket is not readable + dispatched = false; + event_loop + .dispatch(Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(!dispatched); + } + + #[test] + fn kill_source() { + let mut event_loop = EventLoop::>>::new().unwrap(); + + let handle = event_loop.handle(); + let (ping, ping_source) = make_ping().unwrap(); + let source = event_loop + .handle() + .insert_source(ping_source, move |(), &mut (), opt_src| { + if let Some(src) = opt_src.take() { + handle.kill(src); + } + }) + .unwrap(); + + ping.ping(); + + let mut opt_src = Some(source); + + event_loop + .dispatch(Duration::from_millis(0), &mut opt_src) + .unwrap(); + + assert!(opt_src.is_none()); + } + + #[test] + fn non_static_data() { + use std::sync::mpsc; + + let (sender, receiver) = mpsc::channel(); + + { + struct RefSender<'a>(&'a mpsc::Sender<()>); + let mut ref_sender = RefSender(&sender); + + let mut event_loop = EventLoop::>::new().unwrap(); + let (ping, ping_source) = make_ping().unwrap(); + let _source = event_loop + .handle() + .insert_source(ping_source, |_, _, ref_sender| { + ref_sender.0.send(()).unwrap(); + }) + .unwrap(); + + ping.ping(); + + event_loop + .dispatch(Duration::from_millis(0), &mut ref_sender) + .unwrap(); + } + + receiver.recv().unwrap(); + // sender still usable (e.g. for another EventLoop) + drop(sender); + } + + // A dummy EventSource to test insertion and removal of sources + struct DummySource; + + impl crate::EventSource for DummySource { + type Event = (); + type Metadata = (); + type Ret = (); + + fn process_events( + &mut self, + _: Readiness, + _: Token, + mut callback: F, + ) -> std::io::Result<()> + where + F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + callback((), &mut ()); + Ok(()) + } + + fn register(&mut self, _: &mut Poll, _: Token) -> std::io::Result<()> { + Ok(()) + } + + fn reregister(&mut self, _: &mut Poll, _: Token) -> std::io::Result<()> { + Ok(()) + } + + fn unregister(&mut self, _: &mut Poll) -> std::io::Result<()> { + Ok(()) + } + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sources/channel.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sources/channel.rs new file mode 100644 index 0000000..536939d --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sources/channel.rs @@ -0,0 +1,291 @@ +//! An MPSC channel whose receiving end is an event source +//! +//! Create a channel using `Channel::::new()`, which returns a +//! `Sender` that can be cloned and sent accross threads if `T: Send`, +//! and a `Channel` that can be inserted into an `EventLoop`. It will generate +//! one event per message. + +use std::sync::mpsc; + +use crate::{EventSource, Poll, Readiness, Token}; + +use super::ping::{make_ping, Ping, PingSource}; + +/// The events generated by the channel event source +pub enum Event { + /// A message was received and is bundled here + Msg(T), + /// The channel was closed + /// + /// This means all the `Sender`s associated with this channel + /// have been dropped, no more messages will ever be received. + Closed, +} + +/// The sender end of a channel +/// +/// It can be cloned and sent accross threads (if `T` is). +pub struct Sender { + sender: mpsc::Sender, + ping: Ping, +} + +#[cfg(not(tarpaulin_include))] +impl Clone for Sender { + fn clone(&self) -> Sender { + Sender { + sender: self.sender.clone(), + ping: self.ping.clone(), + } + } +} + +impl Sender { + /// Send a message to the channel + /// + /// This will wake the event loop and deliver an `Event::Msg` to + /// it containing the provided value. + pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { + self.sender.send(t).map(|()| self.ping.ping()) + } +} + +impl Drop for Sender { + fn drop(&mut self) { + // ping on drop, to notify about channel closure + self.ping.ping(); + } +} + +/// The sender end of a synchronous channel +/// +/// It can be cloned and sent accross threads (if `T` is). +pub struct SyncSender { + sender: mpsc::SyncSender, + ping: Ping, +} + +#[cfg(not(tarpaulin_include))] +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + SyncSender { + sender: self.sender.clone(), + ping: self.ping.clone(), + } + } +} + +impl SyncSender { + /// Send a message to the synchronous channel + /// + /// This will wake the event loop and deliver an `Event::Msg` to + /// it containing the provided value. If the channel is full, this + /// function will block until the event loop empties it and it can + /// deliver the message. + /// + /// Due to the blocking behavior, this method should not be used on the + /// same thread as the one running the event loop, as it could cause deadlocks. + pub fn send(&self, t: T) -> Result<(), mpsc::SendError> { + let ret = self.try_send(t); + match ret { + Ok(()) => Ok(()), + Err(mpsc::TrySendError::Full(t)) => self.sender.send(t).map(|()| self.ping.ping()), + Err(mpsc::TrySendError::Disconnected(t)) => Err(mpsc::SendError(t)), + } + } + + /// Send a message to the synchronous channel + /// + /// This will wake the event loop and deliver an `Event::Msg` to + /// it containing the provided value. If the channel is full, this + /// function will return an error, but the event loop will still be + /// signaled for readiness. + pub fn try_send(&self, t: T) -> Result<(), mpsc::TrySendError> { + let ret = self.sender.try_send(t); + if let Ok(()) | Err(mpsc::TrySendError::Full(_)) = ret { + self.ping.ping(); + } + ret + } +} + +/// The receiving end of the channel +/// +/// This is the event source to be inserted into your `EventLoop`. +pub struct Channel { + receiver: mpsc::Receiver, + source: PingSource, +} + +// This impl is safe because the Channel is only able to move around threads +// when it is not inserted into an event loop. (Otherwise it is stuck into +// a Source<_> and the internals of calloop, which are not Send). +// At this point, the Arc has a count of 1, and it is obviously +// safe to Send between threads. +unsafe impl Send for Channel {} + +/// Create a new asynchronous channel +pub fn channel() -> (Sender, Channel) { + let (sender, receiver) = mpsc::channel(); + let (ping, source) = make_ping().expect("Failed to create a Ping."); + (Sender { sender, ping }, Channel { receiver, source }) +} + +/// Create a new synchronous, bounded channel +pub fn sync_channel(bound: usize) -> (SyncSender, Channel) { + let (sender, receiver) = mpsc::sync_channel(bound); + let (ping, source) = make_ping().expect("Failed to create a Ping."); + (SyncSender { sender, ping }, Channel { receiver, source }) +} + +impl EventSource for Channel { + type Event = Event; + type Metadata = (); + type Ret = (); + + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + mut callback: C, + ) -> std::io::Result<()> + where + C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + let receiver = &self.receiver; + self.source + .process_events(readiness, token, |(), &mut ()| loop { + match receiver.try_recv() { + Ok(val) => callback(Event::Msg(val), &mut ()), + Err(mpsc::TryRecvError::Empty) => break, + Err(mpsc::TryRecvError::Disconnected) => { + callback(Event::Closed, &mut ()); + break; + } + } + }) + } + + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.source.register(poll, token) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.source.reregister(poll, token) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + self.source.unregister(poll) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic_channel() { + let mut event_loop = crate::EventLoop::new().unwrap(); + + let handle = event_loop.handle(); + + let (tx, rx) = channel::<()>(); + + // (got_msg, got_closed) + let mut got = (false, false); + + let _source = handle + .insert_source(rx, move |evt, &mut (), got: &mut (bool, bool)| match evt { + Event::Msg(()) => { + got.0 = true; + } + Event::Closed => { + got.1 = true; + } + }) + .map_err(Into::::into) + .unwrap(); + + // nothing is sent, nothing is received + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut got) + .unwrap(); + + assert_eq!(got, (false, false)); + + // a message is send + tx.send(()).unwrap(); + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut got) + .unwrap(); + + assert_eq!(got, (true, false)); + + // the sender is dropped + ::std::mem::drop(tx); + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut got) + .unwrap(); + + assert_eq!(got, (true, true)); + } + + #[test] + fn basic_sync_channel() { + let mut event_loop = crate::EventLoop::new().unwrap(); + + let handle = event_loop.handle(); + + let (tx, rx) = sync_channel::<()>(2); + + let mut received = (0, false); + + let _source = handle + .insert_source( + rx, + move |evt, &mut (), received: &mut (u32, bool)| match evt { + Event::Msg(()) => { + received.0 += 1; + } + Event::Closed => { + received.1 = true; + } + }, + ) + .map_err(Into::::into) + .unwrap(); + + // nothing is sent, nothing is received + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut received) + .unwrap(); + + assert_eq!(received.0, 0); + assert!(!received.1); + + // fill the channel + tx.send(()).unwrap(); + tx.send(()).unwrap(); + assert!(tx.try_send(()).is_err()); + + // empty it + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut received) + .unwrap(); + + assert_eq!(received.0, 2); + assert!(!received.1); + + // send a final message and drop the sender + tx.send(()).unwrap(); + std::mem::drop(tx); + + // final read of the channel + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut received) + .unwrap(); + + assert_eq!(received.0, 3); + assert!(received.1); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sources/generic.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sources/generic.rs new file mode 100644 index 0000000..4c5f5ca --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sources/generic.rs @@ -0,0 +1,207 @@ +//! A generic event source wrapping a file descriptor +//! +//! You can use this general purpose adapter around file descriptor +//! to insert your own file descriptors into an event loop. +//! +//! It can also help you implementing your own event sources: just have +//! these `Generic<_>` as fields of your event source, and delegate the +//! `EventSource` implementation to them. + +use std::io; +#[cfg(unix)] +use std::os::unix::io::{AsRawFd, RawFd}; + +use crate::{EventSource, Interest, Mode, Poll, Readiness, Token}; + +/// A generic event source wrapping a FD-backed type +pub struct Generic { + /// The wrapped FD-backed type + pub file: F, + /// The programmed interest + pub interest: Interest, + /// The programmed mode + pub mode: Mode, +} + +/// A wrapper to insert a raw file descriptor into a `Generic` event source +pub struct Fd(pub RawFd); + +impl AsRawFd for Fd { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +impl Generic { + /// Wrap a FD-backed type into a `Generic` event source + pub fn new(file: F, interest: Interest, mode: Mode) -> Generic { + Generic { + file, + interest, + mode, + } + } + + /// Unwrap the `Generic` source to retrieve the underlying type + pub fn unwrap(self) -> F { + self.file + } +} + +impl Generic { + /// Wrap a raw file descriptor into a `Generic` event source + pub fn from_fd(fd: RawFd, interest: Interest, mode: Mode) -> Generic { + Self::new(Fd(fd), interest, mode) + } +} + +impl EventSource for Generic { + type Event = Readiness; + type Metadata = F; + type Ret = io::Result<()>; + + fn process_events( + &mut self, + readiness: Readiness, + _: Token, + mut callback: C, + ) -> std::io::Result<()> + where + C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + callback(readiness, &mut self.file) + } + + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + poll.register(self.file.as_raw_fd(), self.interest, self.mode, token) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + poll.reregister(self.file.as_raw_fd(), self.interest, self.mode, token) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + poll.unregister(self.file.as_raw_fd()) + } +} + +#[cfg(test)] +mod test { + use std::io::{self, Read, Write}; + + use super::Generic; + use crate::{Interest, Mode}; + #[cfg(unix)] + #[test] + fn dispatch_unix() { + use std::os::unix::net::UnixStream; + + let mut event_loop = crate::EventLoop::new().unwrap(); + + let handle = event_loop.handle(); + + let (mut tx, rx) = UnixStream::pair().unwrap(); + + let generic = Generic::new(rx, Interest::Readable, Mode::Level); + + let mut dispached = false; + + let _source = handle + .insert_source(generic, move |readiness, file, d| { + assert!(readiness.readable); + // we have not registered for writability + assert!(!readiness.writable); + let mut buffer = vec![0; 10]; + let ret = file.read(&mut buffer).unwrap(); + assert_eq!(ret, 6); + assert_eq!(&buffer[..6], &[1, 2, 3, 4, 5, 6]); + + *d = true; + Ok(()) + }) + .map_err(Into::::into) + .unwrap(); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) + .unwrap(); + + assert!(!dispached); + + tx.write(&[1, 2, 3, 4, 5, 6]).unwrap(); + tx.flush().unwrap(); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) + .unwrap(); + + assert!(dispached); + } + + #[test] + fn register_deregister_unix() { + use std::os::unix::net::UnixStream; + + let mut event_loop = crate::EventLoop::new().unwrap(); + + let handle = event_loop.handle(); + + let (mut tx, rx) = UnixStream::pair().unwrap(); + + let generic = Generic::new(rx, Interest::Readable, Mode::Level); + + let mut dispached = false; + + let source = handle + .insert_source(generic, move |_, _, d| { + *d = true; + Ok(()) + }) + .map_err(Into::::into) + .unwrap(); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) + .unwrap(); + + assert!(!dispached); + + // remove the source, and then write something + + let generic = event_loop.handle().remove(source); + + tx.write(&[1, 2, 3, 4, 5, 6]).unwrap(); + tx.flush().unwrap(); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) + .unwrap(); + + // the source has not been dispatched, as the source is no longer here + assert!(!dispached); + + // insert it again + let _source = handle + .insert_source(generic, move |readiness, file, d| { + assert!(readiness.readable); + // we have not registered for writability + assert!(!readiness.writable); + let mut buffer = vec![0; 10]; + let ret = file.read(&mut buffer).unwrap(); + assert_eq!(ret, 6); + assert_eq!(&buffer[..6], &[1, 2, 3, 4, 5, 6]); + + *d = true; + Ok(()) + }) + .map_err(Into::::into) + .unwrap(); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(0)), &mut dispached) + .unwrap(); + + // the has now been properly dispatched + assert!(dispached); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sources/mod.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sources/mod.rs new file mode 100644 index 0000000..d64acea --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sources/mod.rs @@ -0,0 +1,204 @@ +use std::{cell::RefCell, rc::Rc}; + +use crate::{Poll, Readiness, Token}; + +pub mod channel; +pub mod generic; +pub mod ping; +#[cfg(target_os = "linux")] +pub mod signals; +pub mod timer; + +/// Trait representing an event source +/// +/// This is the trait you need to implement if you wish to create your own +/// calloop-compatible event sources. +/// +/// The 3 type parameter define the type of closure the user will need to +/// provide to process events for your event source. +/// +/// The `process_events` method will be called when one of the FD you registered +/// is ready, with the associated readiness and token. +/// +/// The last 3 methods are plumbing to let your source register itself with the +/// polling system. See their documentation for details. +pub trait EventSource { + /// The type of events generated by your source. + type Event; + /// Some metadata of your event source + /// + /// This is typically useful if your source contains some internal state that + /// the user may need to interact with when processing events. The user callback + /// will receive a `&mut Metadata` reference. + /// + /// Just set to `()` if not needed. + type Metadata; + /// The return type of the user callback + /// + /// If the user needs to return some value back to your event source once its + /// processing is finshed (to indicate success or failure for example), you can + /// specify it using this type. + /// + /// Just set to `()` if not needed. + type Ret; + + /// Process any relevant events + /// + /// This method will be called every time one of the FD you registered becomes + /// ready, including the readiness details and the associated token. + /// + /// Your event source will then do some processing of the file descriptor(s) to generate + /// events, and call the provided `callback` for each one of them. + /// + /// You should ensure you drained the file descriptors of their events, especially if using + /// edge-triggered mode. + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + callback: F, + ) -> std::io::Result<()> + where + F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret; + + /// Register yourself to this poll instance + /// + /// You should register all your relevant file descriptors to the provided `Poll` + /// using its `Poll::register` method. + /// + /// If you need to register more than one file descriptor, you can change the + /// `sub_id` field of the `Token` to differentiate between them. + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()>; + + /// Re-register your file descriptors + /// + /// Your should update the registration of all your relevant file descriptor to + /// the provided `Poll` using its `Poll::reregister`, if necessary. + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()>; + + /// Unregister your file descriptors + /// + /// You should unregister all your file descriptors from this `Poll` using its + /// `Poll::unregister` method. + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()>; +} + +pub(crate) struct Dispatcher { + source: S, + callback: F, +} + +impl Dispatcher { + pub fn new(source: S, callback: F) -> Self { + Dispatcher { source, callback } + } +} + +impl EventDispatcher for RefCell> +where + S: EventSource + 'static, + F: FnMut(S::Event, &mut S::Metadata, &mut Data) -> S::Ret, +{ + fn process_events( + &self, + readiness: Readiness, + token: Token, + data: &mut Data, + ) -> std::io::Result<()> { + let mut disp = self.borrow_mut(); + let Dispatcher { + ref mut source, + ref mut callback, + .. + } = *disp; + source.process_events(readiness, token, |event, meta| callback(event, meta, data)) + } + + fn register(&self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.borrow_mut().source.register(poll, token) + } + + fn reregister(&self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.borrow_mut().source.reregister(poll, token) + } + + fn unregister(&self, poll: &mut Poll) -> std::io::Result<()> { + self.borrow_mut().source.unregister(poll) + } + + fn as_source_any(&self) -> std::cell::RefMut { + std::cell::RefMut::map(self.borrow_mut(), |disp| &mut disp.source) + } + + fn into_source_any(self: Rc) -> Box { + let me = Rc::try_unwrap(self).unwrap_or_else(|_| panic!("Unwrapping a shared source.")); + Box::new(me.into_inner().source) + } +} + +pub(crate) trait EventDispatcher { + fn process_events( + &self, + readiness: Readiness, + token: Token, + data: &mut Data, + ) -> std::io::Result<()>; + + fn register(&self, poll: &mut Poll, token: Token) -> std::io::Result<()>; + + fn reregister(&self, poll: &mut Poll, token: Token) -> std::io::Result<()>; + + fn unregister(&self, poll: &mut Poll) -> std::io::Result<()>; + + fn as_source_any(&self) -> std::cell::RefMut; + + fn into_source_any(self: Rc) -> Box; +} + +/// A token representing an event source inserted in the event loop +/// +/// You'll need it to interact with your source via `LoopHandle` +pub struct Source { + pub(crate) token: Token, + pub(crate) _type: std::marker::PhantomData<*const S>, +} + +/// An idle callback that was inserted in this loop +/// +/// This handle allows you to cancel the callback. Dropping +/// it will *not* cancel it. +pub struct Idle { + pub(crate) callback: Rc>, +} + +impl Idle { + /// Cancel the idle callback if it was not already run + pub fn cancel(self) { + self.callback.borrow_mut().cancel(); + } +} + +pub(crate) trait CancellableIdle { + fn cancel(&mut self); +} + +impl CancellableIdle for Option { + fn cancel(&mut self) { + self.take(); + } +} + +pub(crate) trait IdleDispatcher { + fn dispatch(&mut self, data: &mut Data); +} + +impl IdleDispatcher for Option +where + F: FnMut(&mut Data), +{ + fn dispatch(&mut self, data: &mut Data) { + if let Some(callabck) = self.as_mut() { + callabck(data); + } + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sources/ping.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sources/ping.rs new file mode 100644 index 0000000..efc785d --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sources/ping.rs @@ -0,0 +1,167 @@ +//! Ping to the event loop +//! +//! This is an event source that just produces `()` events whevener +//! the associated `Ping::ping()` method is called. If the event source +//! is pinged multiple times between a single dispatching, it'll only generate +//! one event. +//! +//! This event loop is a simple way of waking up the event loop from an +//! other part of your program (and is what backs the `LoopSignal`). It can +//! also be used as a building block to construct event sources whose source +//! of event is not file descriptor, but rather an userspace source +//! (like an other thread). + +use std::{os::unix::io::RawFd, sync::Arc}; + +use nix::{ + fcntl::OFlag, + unistd::{close, pipe2, read, write}, +}; + +use super::generic::{Fd, Generic}; +use crate::{no_nix_err, EventSource, Interest, Mode, Poll, Readiness, Token}; + +/// Create a new ping event source +/// +/// you are given a `Ping` instance, which can be cloned and used to ping the +/// event loop, and a `PingSource`, which you can isnert in your event loop to +/// receive the pings. +pub fn make_ping() -> std::io::Result<(Ping, PingSource)> { + let (read, write) = pipe2(OFlag::O_CLOEXEC | OFlag::O_NONBLOCK).map_err(no_nix_err)?; + let source = PingSource { + pipe: Generic::from_fd(read, Interest::Readable, Mode::Level), + }; + let ping = Ping { + pipe: Arc::new(CloseOnDrop(write)), + }; + Ok((ping, source)) +} + +/// The ping event source +/// +/// You can insert it in your event loop to receive pings. +pub struct PingSource { + pipe: Generic, +} + +impl EventSource for PingSource { + type Event = (); + type Metadata = (); + type Ret = (); + + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + mut callback: C, + ) -> std::io::Result<()> + where + C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + self.pipe + .process_events(readiness, token, |_, &mut Fd(fd)| { + let mut buf = [0u8; 32]; + let mut read_something = false; + loop { + match read(fd, &mut buf) { + Ok(0) => break, // closed pipe, we are now inert + Ok(_) => read_something = true, + Err(e) => { + let e = no_nix_err(e); + if e.kind() == std::io::ErrorKind::WouldBlock { + break; + // nothing more to read + } else { + // propagate error + return Err(e); + } + } + } + } + if read_something { + callback((), &mut ()); + } + Ok(()) + }) + } + + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.pipe.register(poll, token) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.pipe.reregister(poll, token) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + self.pipe.unregister(poll) + } +} + +impl Drop for PingSource { + fn drop(&mut self) { + if let Err(e) = close(self.pipe.file.0) { + log::warn!("[calloop] Failed to close read ping: {:?}", e); + } + } +} + +/// The Ping handle +/// +/// This handle can be cloned and sent accross threads. It can be used to +/// send pings to the `PingSource`. +#[derive(Clone)] +pub struct Ping { + pipe: Arc, +} + +impl Ping { + /// Send a ping to the `PingSource` + pub fn ping(&self) { + if let Err(e) = write(self.pipe.0, &[0u8]) { + log::warn!("[calloop] Failed to write a ping: {:?}", e); + } + } +} + +struct CloseOnDrop(RawFd); + +impl Drop for CloseOnDrop { + fn drop(&mut self) { + if let Err(e) = close(self.0) { + log::warn!("[calloop] Failed to close write ping: {:?}", e); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ping() { + let mut event_loop = crate::EventLoop::::new().unwrap(); + + let (ping, source) = make_ping().unwrap(); + + event_loop + .handle() + .insert_source(source, |(), &mut (), dispatched| *dispatched = true) + .unwrap(); + + ping.ping(); + + let mut dispatched = false; + event_loop + .dispatch(std::time::Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(dispatched); + + // Ping has been drained an no longer generates events + let mut dispatched = false; + event_loop + .dispatch(std::time::Duration::from_millis(0), &mut dispatched) + .unwrap(); + assert!(!dispatched); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sources/signals.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sources/signals.rs new file mode 100644 index 0000000..3ae8bed --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sources/signals.rs @@ -0,0 +1,165 @@ +//! Event source for tracking Unix signals +//! +//! Only available on Linux. +//! +//! This allows you to track and receive Unix signals through the event loop +//! rather than by registering signal handlers. It uses `signalfd` under the hood. +//! +//! The source will take care of masking and unmasking signals for the thread it runs on, +//! but you are responsible for masking them on other threads if you run them. The simplest +//! way to ensure that is to setup the signal event source before spawning any thread, as +//! they'll inherit their parent signal mask. + +use std::convert::TryFrom; +use std::io; +use std::os::raw::c_int; + +use nix::sys::signal::SigSet; +pub use nix::sys::signal::Signal; +pub use nix::sys::signalfd::siginfo; +use nix::sys::signalfd::{SfdFlags, SignalFd}; + +use super::generic::Generic; +use crate::{no_nix_err, EventSource, Interest, Mode, Poll, Readiness, Token}; + +/// An event generated by the signal event source +#[derive(Copy, Clone)] +pub struct Event { + info: siginfo, +} + +impl Event { + /// Retrieve the signal number that was receive + pub fn signal(&self) -> Signal { + Signal::try_from(self.info.ssi_signo as c_int).unwrap() + } + + /// Access the full `siginfo_t` associated with this signal event + pub fn full_info(&self) -> siginfo { + self.info + } +} + +/// An event source for receiving Unix signals +pub struct Signals { + sfd: Generic, + mask: SigSet, +} + +impl Signals { + /// Create a new signal event source listening on the specified list of signals + pub fn new(signals: &[Signal]) -> io::Result { + let mut mask = SigSet::empty(); + for &s in signals { + mask.add(s); + } + + // Mask the signals for this thread + mask.thread_block().map_err(no_nix_err)?; + // Create the SignalFd + let sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK | SfdFlags::SFD_CLOEXEC) + .map_err(no_nix_err)?; + + Ok(Signals { + sfd: Generic::new(sfd, Interest::Readable, Mode::Level), + mask, + }) + } + + /// Add a list of signals to the signals source + /// + /// If this function returns an error, the signal mask of the thread may + /// have still been changed. + pub fn add_signals(&mut self, signals: &[Signal]) -> io::Result<()> { + for &s in signals { + self.mask.add(s); + } + self.mask.thread_block().map_err(no_nix_err)?; + self.sfd.file.set_mask(&self.mask).map_err(no_nix_err)?; + Ok(()) + } + + /// Remove a list of signals to the signals source + /// + /// If this function returns an error, the signal mask of the thread may + /// have still been changed. + pub fn remove_signals(&mut self, signals: &[Signal]) -> io::Result<()> { + let mut removed = SigSet::empty(); + for &s in signals { + self.mask.remove(s); + removed.add(s); + } + removed.thread_unblock().map_err(no_nix_err)?; + self.sfd.file.set_mask(&self.mask).map_err(no_nix_err)?; + Ok(()) + } + + /// Replace the list of signals of the source + /// + /// If this function returns an error, the signal mask of the thread may + /// have still been changed. + pub fn set_signals(&mut self, signals: &[Signal]) -> io::Result<()> { + let mut new_mask = SigSet::empty(); + for &s in signals { + new_mask.add(s); + } + + self.mask.thread_unblock().map_err(no_nix_err)?; + new_mask.thread_block().map_err(no_nix_err)?; + self.sfd.file.set_mask(&new_mask).map_err(no_nix_err)?; + self.mask = new_mask; + + Ok(()) + } +} + +impl Drop for Signals { + fn drop(&mut self) { + // we cannot handle error here + if let Err(e) = self.mask.thread_unblock() { + log::warn!("[calloop] Failed to unmask signals: {:?}", e); + } + } +} + +impl EventSource for Signals { + type Event = Event; + type Metadata = (); + type Ret = (); + + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + mut callback: C, + ) -> std::io::Result<()> + where + C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + self.sfd.process_events(readiness, token, |_, sfd| { + loop { + match sfd.read_signal() { + Ok(Some(info)) => callback(Event { info }, &mut ()), + Ok(None) => break, + Err(e) => { + log::warn!("[callop] Error reading from signalfd: {}", e); + return Err(no_nix_err(e)); + } + } + } + Ok(()) + }) + } + + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.sfd.register(poll, token) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.sfd.reregister(poll, token) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + self.sfd.unregister(poll) + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sources/timer.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sources/timer.rs new file mode 100644 index 0000000..bca9057 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sources/timer.rs @@ -0,0 +1,487 @@ +//! Timer-based event sources +//! +//! A `Timer` is a general time-tracking object. It is used by setting timeouts, +//! and generates events whenever a timeout expires. +//! +//! The `Timer` event source provides an handle `TimerHandle`, which is used +//! to set or cancel timeouts. This handle is cloneable and can be send accross threads +//! if `T: Send`, allowing you to setup timeouts from any point of your program. + +use std::cell::RefCell; +use std::collections::BinaryHeap; +use std::io; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Mutex, +}; +use std::time::{Duration, Instant}; + +use super::ping::{make_ping, PingSource}; +use crate::{EventSource, Poll, Readiness, Token}; + +/// A Timer event source +/// +/// It generates events of type `(T, TimerHandle)`, providing you +/// an handle inside the event callback, allowing you to set new timeouts +/// as a response to a timeout being reached (for reccuring ticks for example). +pub struct Timer { + inner: Arc>>, + source: TimerSource, +} + +impl Timer { + /// Create a new timer with default parameters + /// + /// Default time resolution is 100ms + pub fn new() -> std::io::Result> { + let (scheduler, source) = TimerScheduler::new()?; + let inner = TimerInner::new(scheduler); + Ok(Timer { + inner: Arc::new(Mutex::new(inner)), + source, + }) + } + + /// Get an handle for this timer + pub fn handle(&self) -> TimerHandle { + TimerHandle { + inner: self.inner.clone(), + } + } +} + +/// An handle to a timer, used to set or cancel timeouts +/// +/// This handle can be cloned, and can be sent accross thread as long +/// as `T: Send`. +pub struct TimerHandle { + inner: Arc>>, +} + +// Manual impl of `Clone` as #[derive(Clone)] adds a `T: Clone` bound +#[cfg(not(tarpaulin_include))] +impl Clone for TimerHandle { + fn clone(&self) -> TimerHandle { + TimerHandle { + inner: self.inner.clone(), + } + } +} + +/// An itentifier to cancel a timeout if necessary +pub struct Timeout { + counter: u32, +} + +impl TimerHandle { + /// Set a new timeout + /// + /// The associated `data` will be given as argument to the callback. + /// + /// The returned `Timeout` can be used to cancel it. You can drop it if you don't + /// plan to cancel this timeout. + pub fn add_timeout(&self, delay_from_now: Duration, data: T) -> Timeout { + self.inner + .lock() + .unwrap() + .insert(Instant::now() + delay_from_now, data) + } + + /// Cancel a previsouly set timeout and retrieve the associated data + /// + /// This method returns `None` if the timeout does not exist (it has already fired + /// or has already been cancelled). + pub fn cancel_timeout(&self, timeout: &Timeout) -> Option { + self.inner.lock().unwrap().cancel(timeout) + } + + /// Cancel all planned timeouts for this timer + /// + /// All associated data will be dropped. + pub fn cancel_all_timeouts(&self) { + self.inner.lock().unwrap().cancel_all(); + } +} + +impl EventSource for Timer { + type Event = T; + type Metadata = TimerHandle; + type Ret = (); + + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + mut callback: C, + ) -> std::io::Result<()> + where + C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + let mut handle = TimerHandle { + inner: self.inner.clone(), + }; + let inner = &self.inner; + self.source.process_events(readiness, token, |(), &mut ()| { + let mut some_expired = false; + loop { + let next_expired: Option = { + let mut guard = inner.lock().unwrap(); + guard.next_expired() + }; + if let Some(val) = next_expired { + some_expired = true; + callback(val, &mut handle); + } else { + break; + } + } + // now compute the next timeout and signal if necessary + if some_expired { + inner.lock().unwrap().reschedule(); + } + }) + } + + fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.source.register(poll, token) + } + + fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { + self.source.reregister(poll, token) + } + + fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { + self.source.unregister(poll) + } +} + +/* + * Timer logic + */ + +struct TimeoutData { + deadline: Instant, + data: RefCell>, + counter: u32, +} + +struct TimerInner { + heap: BinaryHeap>, + scheduler: TimerScheduler, + counter: u32, +} + +impl TimerInner { + fn new(scheduler: TimerScheduler) -> TimerInner { + TimerInner { + heap: BinaryHeap::new(), + scheduler, + counter: 0, + } + } + + fn insert(&mut self, deadline: Instant, value: T) -> Timeout { + self.heap.push(TimeoutData { + deadline, + data: RefCell::new(Some(value)), + counter: self.counter, + }); + let ret = Timeout { + counter: self.counter, + }; + self.counter += 1; + self.reschedule(); + ret + } + + fn cancel(&mut self, timeout: &Timeout) -> Option { + for data in self.heap.iter() { + if data.counter == timeout.counter { + return data.data.borrow_mut().take(); + } + } + self.reschedule(); + None + } + + fn cancel_all(&mut self) { + self.heap.clear(); + self.reschedule(); + } + + fn next_expired(&mut self) -> Option { + let now = Instant::now(); + loop { + // check if there is an expired item + if let Some(ref data) = self.heap.peek() { + if data.deadline > now { + return None; + } + // there is an expired timeout, continue the + // loop body + } else { + return None; + } + + // There is an item in the heap, this unwrap cannot blow + let data = self.heap.pop().unwrap(); + if let Some(val) = data.data.into_inner() { + return Some(val); + } + // otherwise this timeout was cancelled, continue looping + } + } + + fn reschedule(&mut self) { + if let Some(next_deadline) = self.heap.peek().map(|data| data.deadline) { + self.scheduler.reschedule(next_deadline); + } else { + self.scheduler.deschedule(); + } + } +} + +// trait implementations for TimeoutData + +impl std::cmp::Ord for TimeoutData { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + // earlier values have priority + self.deadline.cmp(&other.deadline).reverse() + } +} + +impl std::cmp::PartialOrd for TimeoutData { + fn partial_cmp(&self, other: &Self) -> Option { + // earlier values have priority + Some(self.deadline.cmp(&other.deadline).reverse()) + } +} + +impl std::cmp::PartialEq for TimeoutData { + fn eq(&self, other: &Self) -> bool { + // earlier values have priority + self.deadline == other.deadline + } +} + +impl std::cmp::Eq for TimeoutData {} + +/* + * Scheduling + */ + +struct TimerScheduler { + current_deadline: Arc>>, + kill_switch: Arc, + thread: std::thread::JoinHandle<()>, +} + +type TimerSource = PingSource; + +impl TimerScheduler { + fn new() -> io::Result<(TimerScheduler, TimerSource)> { + let current_deadline = Arc::new(Mutex::new(None::)); + let thread_deadline = current_deadline.clone(); + + let kill_switch = Arc::new(AtomicBool::new(false)); + let thread_kill = kill_switch.clone(); + + let (ping, ping_source) = make_ping()?; + + let thread = std::thread::Builder::new() + .name("calloop timer".into()) + .spawn(move || loop { + // stop if requested + if thread_kill.load(Ordering::Acquire) { + return; + } + // otherwise check the timeout + let opt_deadline: Option = { + // subscope to ensure the mutex does not remain locked while the thread is parked + let guard = thread_deadline.lock().unwrap(); + *guard + }; + if let Some(deadline) = opt_deadline { + if let Some(remaining) = deadline.checked_duration_since(Instant::now()) { + // it is not yet expired, go to sleep until it + std::thread::park_timeout(remaining); + } else { + // it is expired, wake the event loop and go to sleep + ping.ping(); + std::thread::park(); + } + } else { + // there is none, got to sleep + std::thread::park(); + } + })?; + + let scheduler = TimerScheduler { + current_deadline, + kill_switch, + thread, + }; + Ok((scheduler, ping_source)) + } + + fn reschedule(&mut self, new_deadline: Instant) { + let mut deadline_guard = self.current_deadline.lock().unwrap(); + if let Some(current_deadline) = *deadline_guard { + if new_deadline < current_deadline || current_deadline <= Instant::now() { + *deadline_guard = Some(new_deadline); + self.thread.thread().unpark(); + } + } else { + *deadline_guard = Some(new_deadline); + self.thread.thread().unpark(); + } + } + + fn deschedule(&mut self) { + *(self.current_deadline.lock().unwrap()) = None; + } +} + +impl Drop for TimerScheduler { + fn drop(&mut self) { + self.kill_switch.store(true, Ordering::Release); + } +} + +/* + * Tests + */ + +#[cfg(test)] +mod tests { + use std::io; + use std::time::Duration; + + use super::*; + + #[test] + fn single_timer() { + let mut event_loop = crate::EventLoop::new().unwrap(); + + let evl_handle = event_loop.handle(); + + let mut fired = false; + + let timer = Timer::<()>::new().unwrap(); + let timer_handle = timer.handle(); + evl_handle + .insert_source(timer, move |(), _, f| { + *f = true; + }) + .map_err(Into::::into) + .unwrap(); + + timer_handle.add_timeout(Duration::from_millis(300), ()); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(100)), &mut fired) + .unwrap(); + + // it should not have fired yet + assert!(!fired); + + event_loop.dispatch(None, &mut fired).unwrap(); + + // it should have fired now + assert!(fired); + } + + #[test] + fn multi_timout_order() { + let mut event_loop = crate::EventLoop::new().unwrap(); + + let evl_handle = event_loop.handle(); + + let mut fired = Vec::new(); + + let timer = Timer::::new().unwrap(); + let timer_handle = timer.handle(); + + evl_handle + .insert_source(timer, |val, _, fired: &mut Vec| { + fired.push(val); + }) + .map_err(Into::::into) + .unwrap(); + + timer_handle.add_timeout(Duration::from_millis(300), 1); + timer_handle.add_timeout(Duration::from_millis(100), 2); + timer_handle.add_timeout(Duration::from_millis(600), 3); + + // 3 dispatches as each returns once at least one event occured + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(200)), &mut fired) + .unwrap(); + + assert_eq!(&fired, &[2]); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired) + .unwrap(); + + assert_eq!(&fired, &[2, 1]); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(400)), &mut fired) + .unwrap(); + + assert_eq!(&fired, &[2, 1, 3]); + } + + #[test] + fn timer_cancel() { + let mut event_loop = crate::EventLoop::new().unwrap(); + + let evl_handle = event_loop.handle(); + + let mut fired = Vec::new(); + + let timer = Timer::::new().unwrap(); + let timer_handle = timer.handle(); + + evl_handle + .insert_source(timer, |val, _, fired: &mut Vec| fired.push(val)) + .map_err(Into::::into) + .unwrap(); + + let timeout1 = timer_handle.add_timeout(Duration::from_millis(300), 1); + let timeout2 = timer_handle.add_timeout(Duration::from_millis(100), 2); + let timeout3 = timer_handle.add_timeout(Duration::from_millis(600), 3); + + // 3 dispatches as each returns once at least one event occured + // + // The timeouts 1 and 3 and not cancelled right away, but still before they + // fire + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(200)), &mut fired) + .unwrap(); + + assert_eq!(&fired, &[2]); + + // timeout2 has already fired, we cancel timeout1 + assert_eq!(timer_handle.cancel_timeout(&timeout2), None); + assert_eq!(timer_handle.cancel_timeout(&timeout1), Some(1)); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(300)), &mut fired) + .unwrap(); + + assert_eq!(&fired, &[2]); + + // cancel timeout3 + assert_eq!(timer_handle.cancel_timeout(&timeout3), Some(3)); + + event_loop + .dispatch(Some(::std::time::Duration::from_millis(600)), &mut fired) + .unwrap(); + + assert_eq!(&fired, &[2]); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sys/epoll.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sys/epoll.rs new file mode 100644 index 0000000..0214988 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sys/epoll.rs @@ -0,0 +1,92 @@ +use std::{io, os::unix::io::RawFd}; + +use super::{Interest, Mode, PollEvent, Readiness, Token}; +use crate::no_nix_err; + +use nix::sys::epoll; + +pub struct Epoll { + epoll_fd: RawFd, +} + +fn make_flags(interest: Interest, mode: Mode) -> epoll::EpollFlags { + let mut flags = match interest { + Interest::Readable => epoll::EpollFlags::EPOLLIN, + Interest::Writable => epoll::EpollFlags::EPOLLOUT, + Interest::Both => epoll::EpollFlags::EPOLLIN | epoll::EpollFlags::EPOLLOUT, + }; + match mode { + Mode::Level => { /* This is the default */ } + Mode::Edge => flags |= epoll::EpollFlags::EPOLLET, + Mode::OneShot => flags |= epoll::EpollFlags::EPOLLONESHOT, + } + flags +} + +fn flags_to_readiness(flags: epoll::EpollFlags) -> Readiness { + Readiness { + readable: flags.contains(epoll::EpollFlags::EPOLLIN), + writable: flags.contains(epoll::EpollFlags::EPOLLOUT), + error: flags.contains(epoll::EpollFlags::EPOLLERR), + } +} + +impl Epoll { + pub(crate) fn new() -> io::Result { + let epoll_fd = + epoll::epoll_create1(epoll::EpollCreateFlags::EPOLL_CLOEXEC).map_err(no_nix_err)?; + Ok(Epoll { epoll_fd }) + } + + pub(crate) fn poll( + &mut self, + timeout: Option, + ) -> io::Result> { + let mut buffer = [epoll::EpollEvent::empty(); 32]; + let timeout = timeout.map(|d| d.as_millis() as isize).unwrap_or(-1); + let n_ready = epoll::epoll_wait(self.epoll_fd, &mut buffer, timeout).map_err(no_nix_err)?; + let events = buffer + .iter() + .take(n_ready) + .map(|event| PollEvent { + readiness: flags_to_readiness(event.events()), + token: Token::from_u64(event.data()), + }) + .collect(); + Ok(events) + } + + pub fn register( + &mut self, + fd: RawFd, + interest: Interest, + mode: Mode, + token: Token, + ) -> io::Result<()> { + let mut event = epoll::EpollEvent::new(make_flags(interest, mode), token.to_u64()); + epoll::epoll_ctl(self.epoll_fd, epoll::EpollOp::EpollCtlAdd, fd, &mut event) + .map_err(no_nix_err) + } + + pub fn reregister( + &mut self, + fd: RawFd, + interest: Interest, + mode: Mode, + token: Token, + ) -> io::Result<()> { + let mut event = epoll::EpollEvent::new(make_flags(interest, mode), token.to_u64()); + epoll::epoll_ctl(self.epoll_fd, epoll::EpollOp::EpollCtlMod, fd, &mut event) + .map_err(no_nix_err) + } + + pub fn unregister(&mut self, fd: RawFd) -> io::Result<()> { + epoll::epoll_ctl(self.epoll_fd, epoll::EpollOp::EpollCtlDel, fd, None).map_err(no_nix_err) + } +} + +impl Drop for Epoll { + fn drop(&mut self) { + let _ = nix::unistd::close(self.epoll_fd); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sys/kqueue.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sys/kqueue.rs new file mode 100644 index 0000000..dfe2489 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sys/kqueue.rs @@ -0,0 +1,261 @@ +use std::{io, os::unix::io::RawFd}; + +use crate::no_nix_err; +use nix::sys::event::{kevent, kevent_ts, kqueue, EventFilter, EventFlag, FilterFlag, KEvent}; + +use super::{Interest, Mode, PollEvent, Readiness, Token}; + +pub struct Kqueue { + kq: RawFd, +} + +fn mode_to_flag(mode: Mode) -> EventFlag { + match mode { + Mode::Level => EventFlag::empty(), + Mode::OneShot => EventFlag::EV_DISPATCH, + Mode::Edge => EventFlag::EV_CLEAR, + } +} + +impl Kqueue { + pub(crate) fn new() -> io::Result { + let kq = kqueue().map_err(no_nix_err)?; + Ok(Kqueue { kq }) + } + + pub(crate) fn poll( + &mut self, + timeout: Option, + ) -> io::Result> { + let mut buffer = [KEvent::new( + 0, + EventFilter::EVFILT_READ, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ); 32]; + + let nevents = match timeout { + None => kevent_ts(self.kq, &[], &mut buffer, None), + Some(t) => kevent(self.kq, &[], &mut buffer, t.as_millis() as usize), + } + .map_err(no_nix_err)?; + + let ret = buffer + .iter() + .take(nevents) + .map(|event| PollEvent { + readiness: Readiness { + readable: event.filter() == EventFilter::EVFILT_READ, + writable: event.filter() == EventFilter::EVFILT_WRITE, + error: event.flags().contains(EventFlag::EV_ERROR) && event.data() != 0, + }, + token: Token::from_usize(event.udata() as usize), + }) + .collect(); + Ok(ret) + } + + pub fn register( + &mut self, + fd: RawFd, + interest: Interest, + mode: Mode, + token: Token, + ) -> io::Result<()> { + let flags = EventFlag::EV_ADD | EventFlag::EV_RECEIPT | mode_to_flag(mode); + + let changes = [ + KEvent::new( + fd as usize, + EventFilter::EVFILT_WRITE, + flags, + FilterFlag::empty(), + 0, + token.to_usize() as isize, + ), + KEvent::new( + fd as usize, + EventFilter::EVFILT_READ, + flags, + FilterFlag::empty(), + 0, + token.to_usize() as isize, + ), + ]; + + let changes = match interest { + Interest::Readable => &changes[1..], + Interest::Writable => &changes[..1], + Interest::Both => &changes[..], + }; + + let mut out = [ + KEvent::new( + 0, + EventFilter::EVFILT_WRITE, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ), + KEvent::new( + 0, + EventFilter::EVFILT_READ, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ), + ]; + + kevent_ts(self.kq, changes, &mut out, None).map_err(no_nix_err)?; + for o in &out { + if o.flags().contains(EventFlag::EV_ERROR) && o.data() != 0 { + let e = io::Error::from_raw_os_error(o.data() as i32); + return Err(e); + } + } + Ok(()) + } + + pub fn reregister( + &mut self, + fd: RawFd, + interest: Interest, + mode: Mode, + token: Token, + ) -> io::Result<()> { + let write_flags = if interest.contains_write() { + EventFlag::EV_ADD | EventFlag::EV_RECEIPT | mode_to_flag(mode) + } else { + EventFlag::EV_DELETE + }; + let read_flags = if interest.contains_read() { + EventFlag::EV_ADD | EventFlag::EV_RECEIPT | mode_to_flag(mode) + } else { + EventFlag::EV_DELETE + }; + + let changes = [ + KEvent::new( + fd as usize, + EventFilter::EVFILT_WRITE, + write_flags, + FilterFlag::empty(), + 0, + token.to_usize() as isize, + ), + KEvent::new( + fd as usize, + EventFilter::EVFILT_READ, + read_flags, + FilterFlag::empty(), + 0, + token.to_usize() as isize, + ), + ]; + + let mut out = [ + KEvent::new( + 0, + EventFilter::EVFILT_WRITE, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ), + KEvent::new( + 0, + EventFilter::EVFILT_READ, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ), + ]; + + kevent_ts(self.kq, &changes, &mut out, None).map_err(no_nix_err)?; + + for o in &out { + if o.flags().contains(EventFlag::EV_ERROR) && o.data() != 0 { + let e = io::Error::from_raw_os_error(o.data() as i32); + // ignore NotFound error which is raised if we tried to remove a non-existent filter + if e.kind() != io::ErrorKind::NotFound { + return Err(e); + } + } + } + Ok(()) + } + + pub fn unregister(&mut self, fd: RawFd) -> io::Result<()> { + let changes = [ + KEvent::new( + fd as usize, + EventFilter::EVFILT_WRITE, + EventFlag::EV_DELETE, + FilterFlag::empty(), + 0, + 0, + ), + KEvent::new( + fd as usize, + EventFilter::EVFILT_READ, + EventFlag::EV_DELETE, + FilterFlag::empty(), + 0, + 0, + ), + ]; + + let mut out = [ + KEvent::new( + 0, + EventFilter::EVFILT_WRITE, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ), + KEvent::new( + 0, + EventFilter::EVFILT_READ, + EventFlag::empty(), + FilterFlag::empty(), + 0, + 0, + ), + ]; + + kevent_ts(self.kq, &changes, &mut out, None).map_err(no_nix_err)?; + + // Report an error if *both* fd were missing, meaning we were not registered at all + let mut notfound = 0; + + for o in &out { + if o.flags().contains(EventFlag::EV_ERROR) && o.data() != 0 { + let e = io::Error::from_raw_os_error(o.data() as i32); + // ignore NotFound error which is raised if we tried to remove a non-existent filter + if e.kind() != io::ErrorKind::NotFound { + return Err(e); + } else { + notfound += 1; + } + } + } + + if notfound == 2 { + return Err(io::ErrorKind::NotFound.into()); + } + + Ok(()) + } +} + +impl Drop for Kqueue { + fn drop(&mut self) { + let _ = nix::unistd::close(self.kq); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/src/sys/mod.rs b/third_party/cargo/vendor/calloop-0.6.5/src/sys/mod.rs new file mode 100644 index 0000000..01413fd --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/src/sys/mod.rs @@ -0,0 +1,235 @@ +use std::{io, os::unix::io::RawFd}; + +#[cfg(target_os = "linux")] +mod epoll; +#[cfg(target_os = "linux")] +use epoll::Epoll as Poller; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +mod kqueue; +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +use kqueue::Kqueue as Poller; + +/// Possible modes for registering a file descriptor +#[derive(Copy, Clone, Debug)] +pub enum Mode { + /// Single event generation + /// + /// This FD will be disabled as soon as it has generated one event. + /// + /// The user will need to use `LoopHandle::update()` to re-enable it if + /// desired. + OneShot, + /// Level-triggering + /// + /// This FD will report events on every poll as long as the requested interests + /// are available. If the same FD is inserted in multiple event loops, all of + /// them are notified of readiness. + Level, + /// Edge-triggering + /// + /// This FD will report events only when it *gains* one of the requested interests. + /// it must thus be fully processed befor it'll generate events again. If the same + /// FD is inserted on multiple event loops, it may be that not all of them are notified + /// of readiness, and not necessarily always the same(s) (at least one is notified). + Edge, +} + +/// Interest to register regarding the file descriptor +#[derive(Copy, Clone, Debug)] +pub enum Interest { + /// Will generate events when readable + Readable, + /// Will generate events when writable + Writable, + /// Will generate events when readable or writable + Both, +} + +#[allow(dead_code)] +impl Interest { + fn contains_read(self) -> bool { + match self { + Interest::Readable => true, + Interest::Writable => false, + Interest::Both => true, + } + } + + fn contains_write(self) -> bool { + match self { + Interest::Readable => false, + Interest::Writable => true, + Interest::Both => false, + } + } +} + +/// Readiness for a file descriptor notification +#[derive(Copy, Clone, Debug)] +pub struct Readiness { + /// Is the FD readable + pub readable: bool, + /// Is the FD writable + pub writable: bool, + /// Is the FD in an error state + pub error: bool, +} + +pub(crate) struct PollEvent { + pub(crate) readiness: Readiness, + pub(crate) token: Token, +} + +/// A Token for registration +/// +/// This token is given to you by the event loop, and you should +/// forward it to the `Poll` when registering your file descriptors. +/// +/// It also contains a publc field that you can change. In case your event +/// source needs to register more than one FD, you can register each with a +/// different value of the `sub_id` field, to differentiate them. You can then +/// know which of these FD is ready by reading the `sub_id` field of the +/// token you'll be given in the `process_events` method of your source. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Token { + pub(crate) id: u32, + /// The source-internal ID + pub sub_id: u32, +} + +#[allow(dead_code)] +impl Token { + pub(crate) fn to_u64(self) -> u64 { + ((self.id as u64) << 32) + self.sub_id as u64 + } + + pub(crate) fn from_u64(i: u64) -> Token { + Token { + id: (i >> 32) as u32, + sub_id: (i & std::u32::MAX as u64) as u32, + } + } + + pub(crate) fn to_u32(self) -> u32 { + (self.id << 16) + self.sub_id + } + + pub(crate) fn from_u32(i: u32) -> Token { + Token { + id: (i >> 16), + sub_id: (i & std::u16::MAX as u32), + } + } + + #[cfg(target_pointer_width = "64")] + pub(crate) fn to_usize(self) -> usize { + self.to_u64() as usize + } + + #[cfg(target_pointer_width = "32")] + pub(crate) fn to_usize(self) -> usize { + self.to_u32() as usize + } + + #[cfg(target_pointer_width = "64")] + pub(crate) fn from_usize(i: usize) -> Token { + Self::from_u64(i as u64) + } + + #[cfg(target_pointer_width = "32")] + pub(crate) fn from_usize(i: usize) -> Token { + Self::from_u64(i as u64) + } +} + +/// The polling system +/// +/// This type represents the polling system of calloop, on which you +/// can register your file descriptors. This interface is only accessible in +/// implementations of the `EventSource` trait. +/// +/// You only need to interact with this type if you are implementing you +/// own event sources, while implementing the `EventSource` trait. And even in this case, +/// you can often just use the `Generic` event source and delegate the implementations to it. +pub struct Poll { + poller: Poller, +} + +impl Poll { + pub(crate) fn new() -> io::Result { + Ok(Poll { + poller: Poller::new()?, + }) + } + + pub(crate) fn poll( + &mut self, + timeout: Option, + ) -> io::Result> { + self.poller.poll(timeout) + } + + /// Register a new file descriptor for polling + /// + /// The file descriptor will be registered with given interest, + /// mode and token. This function will fail if given a + /// bad file descriptor or if the provided file descriptor is already + /// registered. + pub fn register( + &mut self, + fd: RawFd, + interest: Interest, + mode: Mode, + token: Token, + ) -> io::Result<()> { + self.poller.register(fd, interest, mode, token) + } + + /// Update the registration for a file descriptor + /// + /// This allows you to change the interest, mode or token of a file + /// descriptor. Fails if the provided fd is not currently registered. + pub fn reregister( + &mut self, + fd: RawFd, + interest: Interest, + mode: Mode, + token: Token, + ) -> io::Result<()> { + self.poller.reregister(fd, interest, mode, token) + } + + /// Unregister a file descriptor + /// + /// This file descriptor will no longer generate events. Fails if the + /// provided file descriptor is not currently registered. + pub fn unregister(&mut self, fd: RawFd) -> io::Result<()> { + self.poller.unregister(fd) + } +} + +#[cfg(test)] +mod tests { + use super::Token; + #[test] + fn token_convert() { + let t = Token { + id: 0x1337, + sub_id: 0x42, + }; + assert_eq!(t.to_u64(), 0x0000133700000042); + let t2 = Token::from_u64(0x0000133700000042); + assert_eq!(t, t2); + } +} diff --git a/third_party/cargo/vendor/calloop-0.6.5/tests/signals.rs b/third_party/cargo/vendor/calloop-0.6.5/tests/signals.rs new file mode 100644 index 0000000..9a3b901 --- /dev/null +++ b/third_party/cargo/vendor/calloop-0.6.5/tests/signals.rs @@ -0,0 +1,140 @@ +// These tests cannot run as a regular test because cargo would spawn a thread to run it, +// failing the signal masking. So we make our own, non-threaded harnessing + +#[cfg(target_os = "linux")] +fn main() { + for test in self::test::TESTS { + test(); + // reset the signal mask between tests + self::test::reset_mask(); + } +} + +#[cfg(not(target_os = "linux"))] +fn main() {} + +#[cfg(target_os = "linux")] +mod test { + extern crate calloop; + extern crate nix; + + use std::io; + use std::time::Duration; + + use self::calloop::signals::{Signal, Signals}; + use self::calloop::EventLoop; + + use self::nix::sys::signal::{kill, SigSet}; + use self::nix::unistd::Pid; + + pub const TESTS: &'static [fn()] = &[single_usr1, usr2_added_afterwards, usr2_signal_removed]; + + pub fn reset_mask() { + SigSet::empty().thread_set_mask().unwrap(); + } + + fn single_usr1() { + let mut event_loop = EventLoop::new().unwrap(); + + let mut signal_received = false; + + let _signal_source = event_loop + .handle() + .insert_source( + Signals::new(&[Signal::SIGUSR1]).unwrap(), + move |evt, &mut (), rcv| { + assert!(evt.signal() == Signal::SIGUSR1); + *rcv = true; + }, + ) + .map_err(Into::::into) + .unwrap(); + + // send ourselves a SIGUSR1 + kill(Pid::this(), Signal::SIGUSR1).unwrap(); + + event_loop + .dispatch(Some(Duration::from_millis(10)), &mut signal_received) + .unwrap(); + + assert!(signal_received); + } + + fn usr2_added_afterwards() { + let mut event_loop = EventLoop::new().unwrap(); + + let mut signal_received = None; + + let signal_source = event_loop + .handle() + .insert_source( + Signals::new(&[Signal::SIGUSR1]).unwrap(), + move |evt, &mut (), rcv| { + *rcv = Some(evt.signal()); + }, + ) + .map_err(Into::::into) + .unwrap(); + + event_loop.handle().with_source(&signal_source, |signals| { + signals.add_signals(&[Signal::SIGUSR2]).unwrap() + }); + + // send ourselves a SIGUSR2 + kill(Pid::this(), Signal::SIGUSR2).unwrap(); + + event_loop + .dispatch(Some(Duration::from_millis(10)), &mut signal_received) + .unwrap(); + + assert_eq!(signal_received, Some(Signal::SIGUSR2)); + } + + fn usr2_signal_removed() { + let mut event_loop = EventLoop::new().unwrap(); + + let mut signal_received = None; + + let signal_source = event_loop + .handle() + .insert_source( + Signals::new(&[Signal::SIGUSR1, Signal::SIGUSR2]).unwrap(), + move |evt, &mut (), rcv| { + *rcv = Some(evt.signal()); + }, + ) + .map_err(Into::::into) + .unwrap(); + + event_loop.handle().with_source(&signal_source, |signals| { + signals.remove_signals(&[Signal::SIGUSR2]).unwrap() + }); + + // block sigusr2 anyway, to not be killed by it + let mut set = SigSet::empty(); + set.add(Signal::SIGUSR2); + set.thread_block().unwrap(); + + // send ourselves a SIGUSR2 + kill(Pid::this(), Signal::SIGUSR2).unwrap(); + + event_loop + .dispatch(Some(Duration::from_millis(10)), &mut signal_received) + .unwrap(); + + // we should not have received anything, as we don't listen to SIGUSR2 any more + assert!(signal_received.is_none()); + + // swap the signals from [SIGUSR1] to [SIGUSR2] + event_loop.handle().with_source(&signal_source, |signals| { + signals.set_signals(&[Signal::SIGUSR2]).unwrap() + }); + + event_loop + .dispatch(Some(Duration::from_millis(10)), &mut signal_received) + .unwrap(); + + // we should get back the pending SIGUSR2 now + assert_eq!(signal_received, Some(Signal::SIGUSR2)); + } +} diff --git a/third_party/cargo/vendor/cc-1.0.54/.cargo-checksum.json b/third_party/cargo/vendor/cc-1.0.54/.cargo-checksum.json deleted file mode 100644 index 6081516..0000000 --- a/third_party/cargo/vendor/cc-1.0.54/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"6ceb0c97cec493a896bf37a9f6f04ea14764277ecc219ac9977199bcdded3805","Cargo.toml":"ee16287327f8bf448537e3058c2bbd17df281f52404928b9b7f50f2191dc09cd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"7184fbdf375a057e673257348f6d7584c0dd11b66318d98f3647f69eb610b097","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"516506ab998fc0dbc82b0ebd39446f80d92f76e7937a0d7adfe1b91e12ba54b2","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"2b69dd43b5d414fca7a8e50a046cb2cf4c7fe80b9eb6a2e67538a859c597a805","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cc-1.0.54/BUILD.bazel b/third_party/cargo/vendor/cc-1.0.54/BUILD.bazel deleted file mode 100644 index 0767777..0000000 --- a/third_party/cargo/vendor/cc-1.0.54/BUILD.bazel +++ /dev/null @@ -1,86 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_binary( - # Prefix bin name to disambiguate from (probable) collision with lib name - # N.B.: The exact form of this is subject to change. - name = "cargo_bin_gcc_shim", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/bin/gcc-shim.rs", - data = [], - edition = "2018", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.0.54", - # buildifier: leave-alone - deps = [ - # Binaries get an implicit dependency on their crate's lib - ":cc", - ], -) - -rust_library( - name = "cc", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2018", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.0.54", - # buildifier: leave-alone - deps = [ - ], -) - -# Unsupported target "cc_env" with type "test" omitted - -# Unsupported target "cflags" with type "test" omitted - -# Unsupported target "cxxflags" with type "test" omitted - -# Unsupported target "test" with type "test" omitted diff --git a/third_party/cargo/vendor/cc-1.0.54/Cargo.lock b/third_party/cargo/vendor/cc-1.0.54/Cargo.lock deleted file mode 100644 index 7fa572a..0000000 --- a/third_party/cargo/vendor/cc-1.0.54/Cargo.lock +++ /dev/null @@ -1,156 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.54" -dependencies = [ - "jobserver 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getrandom" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "jobserver" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.66" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ppv-lite86" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "remove_dir_all" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempfile" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum jobserver 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "230ae9adf468173aecd4176c7233bddc84a15871a586c5971ace9a55f881c075" -"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/cargo/vendor/cc-1.0.54/Cargo.toml b/third_party/cargo/vendor/cc-1.0.54/Cargo.toml deleted file mode 100644 index 22cd41a..0000000 --- a/third_party/cargo/vendor/cc-1.0.54/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "cc" -version = "1.0.54" -authors = ["Alex Crichton "] -exclude = ["/.travis.yml", "/appveyor.yml"] -description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" -homepage = "https://github.com/alexcrichton/cc-rs" -documentation = "https://docs.rs/cc" -readme = "README.md" -keywords = ["build-dependencies"] -categories = ["development-tools::build-utils"] -license = "MIT/Apache-2.0" -repository = "https://github.com/alexcrichton/cc-rs" -[dependencies.jobserver] -version = "0.1.16" -optional = true -[dev-dependencies.tempfile] -version = "3" - -[features] -parallel = ["jobserver"] diff --git a/third_party/cargo/vendor/cc-1.0.54/README.md b/third_party/cargo/vendor/cc-1.0.54/README.md deleted file mode 100644 index 68448ac..0000000 --- a/third_party/cargo/vendor/cc-1.0.54/README.md +++ /dev/null @@ -1,194 +0,0 @@ -# cc-rs - -A library to compile C/C++/assembly into a Rust library/application. - -[Documentation](https://docs.rs/cc) - -A simple library meant to be used as a build dependency with Cargo packages in -order to build a set of C/C++ files into a static archive. This crate calls out -to the most relevant compiler for a platform, for example using `cl` on MSVC. - -> **Note**: this crate was recently renamed from the `gcc` crate, so if you're -> looking for the `gcc` crate you're in the right spot! - -## Using cc-rs - -First, you'll want to both add a build script for your crate (`build.rs`) and -also add this crate to your `Cargo.toml` via: - -```toml -[build-dependencies] -cc = "1.0" -``` - -Next up, you'll want to write a build script like so: - -```rust,no_run -// build.rs - -fn main() { - cc::Build::new() - .file("foo.c") - .file("bar.c") - .compile("foo"); -} -``` - -And that's it! Running `cargo build` should take care of the rest and your Rust -application will now have the C files `foo.c` and `bar.c` compiled into a file -named libfoo.a. You can call the functions in Rust by declaring functions in -your Rust code like so: - -``` -extern { - fn foo_function(); - fn bar_function(); -} - -pub fn call() { - unsafe { - foo_function(); - bar_function(); - } -} - -fn main() { - // ... -} -``` - -## External configuration via environment variables - -To control the programs and flags used for building, the builder can set a -number of different environment variables. - -* `CFLAGS` - a series of space separated flags passed to compilers. Note that - individual flags cannot currently contain spaces, so doing - something like: "-L=foo\ bar" is not possible. -* `CC` - the actual C compiler used. Note that this is used as an exact - executable name, so (for example) no extra flags can be passed inside - this variable, and the builder must ensure that there aren't any - trailing spaces. This compiler must understand the `-c` flag. For - certain `TARGET`s, it also is assumed to know about other flags (most - common is `-fPIC`). -* `AR` - the `ar` (archiver) executable to use to build the static library. -* `CRATE_CC_NO_DEFAULTS` - the default compiler flags may cause conflicts in some cross compiling scenarios. Setting this variable will disable the generation of default compiler flags. - -Each of these variables can also be supplied with certain prefixes and suffixes, -in the following prioritized order: - -1. `_` - for example, `CC_x86_64-unknown-linux-gnu` -2. `_` - for example, `CC_x86_64_unknown_linux_gnu` -3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` -4. `` - a plain `CC`, `AR` as above. - -If none of these variables exist, cc-rs uses built-in defaults - -In addition to the above optional environment variables, `cc-rs` has some -functions with hard requirements on some variables supplied by [cargo's -build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, -and `HOST` variables. - -[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script - -## Optional features - -### Parallel - -Currently cc-rs supports parallel compilation (think `make -jN`) but this -feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, -you can change your dependency to: - -```toml -[build-dependencies] -cc = { version = "1.0", features = ["parallel"] } -``` - -By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it -will limit it to the number of cpus on the machine. If you are using cargo, -use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS` -is supplied by cargo. - -## Compile-time Requirements - -To work properly this crate needs access to a C compiler when the build script -is being run. This crate does not ship a C compiler with it. The compiler -required varies per platform, but there are three broad categories: - -* Unix platforms require `cc` to be the C compiler. This can be found by - installing cc/clang on Linux distributions and Xcode on OSX, for example. -* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) - require `cl.exe` to be available and in `PATH`. This is typically found in - standard Visual Studio installations and the `PATH` can be set up by running - the appropriate developer tools shell. -* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) - require `cc` to be available in `PATH`. We recommend the - [MinGW-w64](http://mingw-w64.org) distribution, which is using the - [Win-builds](http://win-builds.org) installation system. - You may also acquire it via - [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure - to install the appropriate architecture corresponding to your installation of - rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible - only with 32-bit rust compiler. - -[msys2-help]: http://github.com/rust-lang/rust#building-on-windows - -## C++ support - -`cc-rs` supports C++ libraries compilation by using the `cpp` method on -`Build`: - -```rust,no_run -fn main() { - cc::Build::new() - .cpp(true) // Switch to C++ library compilation. - .file("foo.cpp") - .compile("libfoo.a"); -} -``` - -When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env -variables are used instead of `CC` and `CFLAGS` and the C++ standard library is -linked to the crate target. - -## CUDA C++ support - -`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method -on `Build` (currently for GNU/Clang toolchains only): - -```rust,no_run -fn main() { - cc::Build::new() - // Switch to CUDA C++ library compilation using NVCC. - .cuda(true) - // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X). - .flag("-gencode").flag("arch=compute_52,code=sm_52") - // Generate code for Maxwell (Jetson TX1). - .flag("-gencode").flag("arch=compute_53,code=sm_53") - // Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp). - .flag("-gencode").flag("arch=compute_61,code=sm_61") - // Generate code for Pascal (Tesla P100). - .flag("-gencode").flag("arch=compute_60,code=sm_60") - // Generate code for Pascal (Jetson TX2). - .flag("-gencode").flag("arch=compute_62,code=sm_62") - .file("bar.cu") - .compile("libbar.a"); -} -``` - -## License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/cc-1.0.54/src/lib.rs b/third_party/cargo/vendor/cc-1.0.54/src/lib.rs deleted file mode 100644 index f46fade..0000000 --- a/third_party/cargo/vendor/cc-1.0.54/src/lib.rs +++ /dev/null @@ -1,2820 +0,0 @@ -//! A library for build scripts to compile custom C code -//! -//! This library is intended to be used as a `build-dependencies` entry in -//! `Cargo.toml`: -//! -//! ```toml -//! [build-dependencies] -//! cc = "1.0" -//! ``` -//! -//! The purpose of this crate is to provide the utility functions necessary to -//! compile C code into a static archive which is then linked into a Rust crate. -//! Configuration is available through the `Build` struct. -//! -//! This crate will automatically detect situations such as cross compilation or -//! other environment variables set by Cargo and will build code appropriately. -//! -//! The crate is not limited to C code, it can accept any source code that can -//! be passed to a C or C++ compiler. As such, assembly files with extensions -//! `.s` (gcc/clang) and `.asm` (MSVC) can also be compiled. -//! -//! [`Build`]: struct.Build.html -//! -//! # Parallelism -//! -//! To parallelize computation, enable the `parallel` feature for the crate. -//! -//! ```toml -//! [build-dependencies] -//! cc = { version = "1.0", features = ["parallel"] } -//! ``` -//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS` -//! environment variable to the desired amount. -//! -//! Cargo will also set this environment variable when executed with the `-jN` flag. -//! -//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can -//! also specify the build parallelism. -//! -//! # Examples -//! -//! Use the `Build` struct to compile `src/foo.c`: -//! -//! ```no_run -//! fn main() { -//! cc::Build::new() -//! .file("src/foo.c") -//! .define("FOO", Some("bar")) -//! .include("src") -//! .compile("foo"); -//! } -//! ``` - -#![doc(html_root_url = "https://docs.rs/cc/1.0")] -#![cfg_attr(test, deny(warnings))] -#![allow(deprecated)] -#![deny(missing_docs)] - -use std::collections::HashMap; -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fmt::{self, Display}; -use std::fs; -use std::io::{self, BufRead, BufReader, Read, Write}; -use std::path::{Path, PathBuf}; -use std::process::{Child, Command, Stdio}; -use std::sync::{Arc, Mutex}; -use std::thread::{self, JoinHandle}; - -// These modules are all glue to support reading the MSVC version from -// the registry and from COM interfaces -#[cfg(windows)] -mod registry; -#[cfg(windows)] -#[macro_use] -mod winapi; -#[cfg(windows)] -mod com; -#[cfg(windows)] -mod setup_config; - -pub mod windows_registry; - -/// A builder for compilation of a native static library. -/// -/// A `Build` is the main type of the `cc` crate and is used to control all the -/// various configuration options and such of a compile. You'll find more -/// documentation on each method itself. -#[derive(Clone, Debug)] -pub struct Build { - include_directories: Vec, - definitions: Vec<(String, Option)>, - objects: Vec, - flags: Vec, - flags_supported: Vec, - known_flag_support_status: Arc>>, - ar_flags: Vec, - no_default_flags: bool, - files: Vec, - cpp: bool, - cpp_link_stdlib: Option>, - cpp_set_stdlib: Option, - cuda: bool, - target: Option, - host: Option, - out_dir: Option, - opt_level: Option, - debug: Option, - force_frame_pointer: Option, - env: Vec<(OsString, OsString)>, - compiler: Option, - archiver: Option, - cargo_metadata: bool, - pic: Option, - use_plt: Option, - static_crt: Option, - shared_flag: Option, - static_flag: Option, - warnings_into_errors: bool, - warnings: Option, - extra_warnings: Option, - env_cache: Arc>>>, -} - -/// Represents the types of errors that may occur while using cc-rs. -#[derive(Clone, Debug)] -enum ErrorKind { - /// Error occurred while performing I/O. - IOError, - /// Invalid architecture supplied. - ArchitectureInvalid, - /// Environment variable not found, with the var in question as extra info. - EnvVarNotFound, - /// Error occurred while using external tools (ie: invocation of compiler). - ToolExecError, - /// Error occurred due to missing external tools. - ToolNotFound, -} - -/// Represents an internal error that occurred, with an explanation. -#[derive(Clone, Debug)] -pub struct Error { - /// Describes the kind of error that occurred. - kind: ErrorKind, - /// More explanation of error that occurred. - message: String, -} - -impl Error { - fn new(kind: ErrorKind, message: &str) -> Error { - Error { - kind: kind, - message: message.to_owned(), - } - } -} - -impl From for Error { - fn from(e: io::Error) -> Error { - Error::new(ErrorKind::IOError, &format!("{}", e)) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}: {}", self.kind, self.message) - } -} - -impl std::error::Error for Error {} - -/// Configuration used to represent an invocation of a C compiler. -/// -/// This can be used to figure out what compiler is in use, what the arguments -/// to it are, and what the environment variables look like for the compiler. -/// This can be used to further configure other build systems (e.g. forward -/// along CC and/or CFLAGS) or the `to_command` method can be used to run the -/// compiler itself. -#[derive(Clone, Debug)] -pub struct Tool { - path: PathBuf, - cc_wrapper_path: Option, - cc_wrapper_args: Vec, - args: Vec, - env: Vec<(OsString, OsString)>, - family: ToolFamily, - cuda: bool, - removed_args: Vec, -} - -/// Represents the family of tools this tool belongs to. -/// -/// Each family of tools differs in how and what arguments they accept. -/// -/// Detection of a family is done on best-effort basis and may not accurately reflect the tool. -#[derive(Copy, Clone, Debug, PartialEq)] -enum ToolFamily { - /// Tool is GNU Compiler Collection-like. - Gnu, - /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags - /// and its cross-compilation approach is different. - Clang, - /// Tool is the MSVC cl.exe. - Msvc { clang_cl: bool }, -} - -impl ToolFamily { - /// What the flag to request debug info for this family of tools look like - fn add_debug_flags(&self, cmd: &mut Tool) { - match *self { - ToolFamily::Msvc { .. } => { - cmd.push_cc_arg("-Z7".into()); - } - ToolFamily::Gnu | ToolFamily::Clang => { - cmd.push_cc_arg("-g".into()); - } - } - } - - /// What the flag to force frame pointers. - fn add_force_frame_pointer(&self, cmd: &mut Tool) { - match *self { - ToolFamily::Gnu | ToolFamily::Clang => { - cmd.push_cc_arg("-fno-omit-frame-pointer".into()); - } - _ => (), - } - } - - /// What the flags to enable all warnings - fn warnings_flags(&self) -> &'static str { - match *self { - ToolFamily::Msvc { .. } => "-W4", - ToolFamily::Gnu | ToolFamily::Clang => "-Wall", - } - } - - /// What the flags to enable extra warnings - fn extra_warnings_flags(&self) -> Option<&'static str> { - match *self { - ToolFamily::Msvc { .. } => None, - ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"), - } - } - - /// What the flag to turn warning into errors - fn warnings_to_errors_flag(&self) -> &'static str { - match *self { - ToolFamily::Msvc { .. } => "-WX", - ToolFamily::Gnu | ToolFamily::Clang => "-Werror", - } - } - - fn verbose_stderr(&self) -> bool { - *self == ToolFamily::Clang - } -} - -/// Represents an object. -/// -/// This is a source file -> object file pair. -#[derive(Clone, Debug)] -struct Object { - src: PathBuf, - dst: PathBuf, -} - -impl Object { - /// Create a new source file -> object file pair. - fn new(src: PathBuf, dst: PathBuf) -> Object { - Object { src: src, dst: dst } - } -} - -impl Build { - /// Construct a new instance of a blank set of configuration. - /// - /// This builder is finished with the [`compile`] function. - /// - /// [`compile`]: struct.Build.html#method.compile - pub fn new() -> Build { - Build { - include_directories: Vec::new(), - definitions: Vec::new(), - objects: Vec::new(), - flags: Vec::new(), - flags_supported: Vec::new(), - known_flag_support_status: Arc::new(Mutex::new(HashMap::new())), - ar_flags: Vec::new(), - no_default_flags: false, - files: Vec::new(), - shared_flag: None, - static_flag: None, - cpp: false, - cpp_link_stdlib: None, - cpp_set_stdlib: None, - cuda: false, - target: None, - host: None, - out_dir: None, - opt_level: None, - debug: None, - force_frame_pointer: None, - env: Vec::new(), - compiler: None, - archiver: None, - cargo_metadata: true, - pic: None, - use_plt: None, - static_crt: None, - warnings: None, - extra_warnings: None, - warnings_into_errors: false, - env_cache: Arc::new(Mutex::new(HashMap::new())), - } - } - - /// Add a directory to the `-I` or include path for headers - /// - /// # Example - /// - /// ```no_run - /// use std::path::Path; - /// - /// let library_path = Path::new("/path/to/library"); - /// - /// cc::Build::new() - /// .file("src/foo.c") - /// .include(library_path) - /// .include("src") - /// .compile("foo"); - /// ``` - pub fn include>(&mut self, dir: P) -> &mut Build { - self.include_directories.push(dir.as_ref().to_path_buf()); - self - } - - /// Specify a `-D` variable with an optional value. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .define("FOO", "BAR") - /// .define("BAZ", None) - /// .compile("foo"); - /// ``` - pub fn define<'a, V: Into>>(&mut self, var: &str, val: V) -> &mut Build { - self.definitions - .push((var.to_string(), val.into().map(|s| s.to_string()))); - self - } - - /// Add an arbitrary object file to link in - pub fn object>(&mut self, obj: P) -> &mut Build { - self.objects.push(obj.as_ref().to_path_buf()); - self - } - - /// Add an arbitrary flag to the invocation of the compiler - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .flag("-ffunction-sections") - /// .compile("foo"); - /// ``` - pub fn flag(&mut self, flag: &str) -> &mut Build { - self.flags.push(flag.to_string()); - self - } - - /// Add an arbitrary flag to the invocation of the compiler - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .file("src/bar.c") - /// .ar_flag("/NODEFAULTLIB:libc.dll") - /// .compile("foo"); - /// ``` - - pub fn ar_flag(&mut self, flag: &str) -> &mut Build { - self.ar_flags.push(flag.to_string()); - self - } - - fn ensure_check_file(&self) -> Result { - let out_dir = self.get_out_dir()?; - let src = if self.cuda { - assert!(self.cpp); - out_dir.join("flag_check.cu") - } else if self.cpp { - out_dir.join("flag_check.cpp") - } else { - out_dir.join("flag_check.c") - }; - - if !src.exists() { - let mut f = fs::File::create(&src)?; - write!(f, "int main(void) {{ return 0; }}")?; - } - - Ok(src) - } - - /// Run the compiler to test if it accepts the given flag. - /// - /// For a convenience method for setting flags conditionally, - /// see `flag_if_supported()`. - /// - /// It may return error if it's unable to run the compilier with a test file - /// (e.g. the compiler is missing or a write to the `out_dir` failed). - /// - /// Note: Once computed, the result of this call is stored in the - /// `known_flag_support` field. If `is_flag_supported(flag)` - /// is called again, the result will be read from the hash table. - pub fn is_flag_supported(&self, flag: &str) -> Result { - let mut known_status = self.known_flag_support_status.lock().unwrap(); - if let Some(is_supported) = known_status.get(flag).cloned() { - return Ok(is_supported); - } - - let out_dir = self.get_out_dir()?; - let src = self.ensure_check_file()?; - let obj = out_dir.join("flag_check"); - let target = self.get_target()?; - let host = self.get_host()?; - let mut cfg = Build::new(); - cfg.flag(flag) - .target(&target) - .opt_level(0) - .host(&host) - .debug(false) - .cpp(self.cpp) - .cuda(self.cuda); - let mut compiler = cfg.try_get_compiler()?; - - // Clang uses stderr for verbose output, which yields a false positive - // result if the CFLAGS/CXXFLAGS include -v to aid in debugging. - if compiler.family.verbose_stderr() { - compiler.remove_arg("-v".into()); - } - - let mut cmd = compiler.to_command(); - let is_arm = target.contains("aarch64") || target.contains("arm"); - let clang = compiler.family == ToolFamily::Clang; - command_add_output_file( - &mut cmd, - &obj, - self.cuda, - target.contains("msvc"), - clang, - false, - is_arm, - ); - - // We need to explicitly tell msvc not to link and create an exe - // in the root directory of the crate - if target.contains("msvc") && !self.cuda { - cmd.arg("-c"); - } - - cmd.arg(&src); - - let output = cmd.output()?; - let is_supported = output.stderr.is_empty(); - - known_status.insert(flag.to_owned(), is_supported); - Ok(is_supported) - } - - /// Add an arbitrary flag to the invocation of the compiler if it supports it - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .flag_if_supported("-Wlogical-op") // only supported by GCC - /// .flag_if_supported("-Wunreachable-code") // only supported by clang - /// .compile("foo"); - /// ``` - pub fn flag_if_supported(&mut self, flag: &str) -> &mut Build { - self.flags_supported.push(flag.to_string()); - self - } - - /// Set the `-shared` flag. - /// - /// When enabled, the compiler will produce a shared object which can - /// then be linked with other objects to form an executable. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .shared_flag(true) - /// .compile("libfoo.so"); - /// ``` - pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build { - self.shared_flag = Some(shared_flag); - self - } - - /// Set the `-static` flag. - /// - /// When enabled on systems that support dynamic linking, this prevents - /// linking with the shared libraries. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .shared_flag(true) - /// .static_flag(true) - /// .compile("foo"); - /// ``` - pub fn static_flag(&mut self, static_flag: bool) -> &mut Build { - self.static_flag = Some(static_flag); - self - } - - /// Disables the generation of default compiler flags. The default compiler - /// flags may cause conflicts in some cross compiling scenarios. - /// - /// Setting the `CRATE_CC_NO_DEFAULTS` environment variable has the same - /// effect as setting this to `true`. The presence of the environment - /// variable and the value of `no_default_flags` will be OR'd together. - pub fn no_default_flags(&mut self, no_default_flags: bool) -> &mut Build { - self.no_default_flags = no_default_flags; - self - } - - /// Add a file which will be compiled - pub fn file>(&mut self, p: P) -> &mut Build { - self.files.push(p.as_ref().to_path_buf()); - self - } - - /// Add files which will be compiled - pub fn files

(&mut self, p: P) -> &mut Build - where - P: IntoIterator, - P::Item: AsRef, - { - for file in p.into_iter() { - self.file(file); - } - self - } - - /// Set C++ support. - /// - /// The other `cpp_*` options will only become active if this is set to - /// `true`. - pub fn cpp(&mut self, cpp: bool) -> &mut Build { - self.cpp = cpp; - self - } - - /// Set CUDA C++ support. - /// - /// Enabling CUDA will pass the detected C/C++ toolchain as an argument to - /// the CUDA compiler, NVCC. NVCC itself accepts some limited GNU-like args; - /// any other arguments for the C/C++ toolchain will be redirected using - /// "-Xcompiler" flags. - /// - /// If enabled, this also implicitly enables C++ support. - pub fn cuda(&mut self, cuda: bool) -> &mut Build { - self.cuda = cuda; - if cuda { - self.cpp = true; - } - self - } - - /// Set warnings into errors flag. - /// - /// Disabled by default. - /// - /// Warning: turning warnings into errors only make sense - /// if you are a developer of the crate using cc-rs. - /// Some warnings only appear on some architecture or - /// specific version of the compiler. Any user of this crate, - /// or any other crate depending on it, could fail during - /// compile time. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .warnings_into_errors(true) - /// .compile("libfoo.a"); - /// ``` - pub fn warnings_into_errors(&mut self, warnings_into_errors: bool) -> &mut Build { - self.warnings_into_errors = warnings_into_errors; - self - } - - /// Set warnings flags. - /// - /// Adds some flags: - /// - "-Wall" for MSVC. - /// - "-Wall", "-Wextra" for GNU and Clang. - /// - /// Enabled by default. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .warnings(false) - /// .compile("libfoo.a"); - /// ``` - pub fn warnings(&mut self, warnings: bool) -> &mut Build { - self.warnings = Some(warnings); - self.extra_warnings = Some(warnings); - self - } - - /// Set extra warnings flags. - /// - /// Adds some flags: - /// - nothing for MSVC. - /// - "-Wextra" for GNU and Clang. - /// - /// Enabled by default. - /// - /// # Example - /// - /// ```no_run - /// // Disables -Wextra, -Wall remains enabled: - /// cc::Build::new() - /// .file("src/foo.c") - /// .extra_warnings(false) - /// .compile("libfoo.a"); - /// ``` - pub fn extra_warnings(&mut self, warnings: bool) -> &mut Build { - self.extra_warnings = Some(warnings); - self - } - - /// Set the standard library to link against when compiling with C++ - /// support. - /// - /// The default value of this property depends on the current target: On - /// OS X `Some("c++")` is used, when compiling for a Visual Studio based - /// target `None` is used and for other targets `Some("stdc++")` is used. - /// If the `CXXSTDLIB` environment variable is set, its value will - /// override the default value. - /// - /// A value of `None` indicates that no automatic linking should happen, - /// otherwise cargo will link against the specified library. - /// - /// The given library name must not contain the `lib` prefix. - /// - /// Common values: - /// - `stdc++` for GNU - /// - `c++` for Clang - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .shared_flag(true) - /// .cpp_link_stdlib("stdc++") - /// .compile("libfoo.so"); - /// ``` - pub fn cpp_link_stdlib<'a, V: Into>>( - &mut self, - cpp_link_stdlib: V, - ) -> &mut Build { - self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); - self - } - - /// Force the C++ compiler to use the specified standard library. - /// - /// Setting this option will automatically set `cpp_link_stdlib` to the same - /// value. - /// - /// The default value of this option is always `None`. - /// - /// This option has no effect when compiling for a Visual Studio based - /// target. - /// - /// This option sets the `-stdlib` flag, which is only supported by some - /// compilers (clang, icc) but not by others (gcc). The library will not - /// detect which compiler is used, as such it is the responsibility of the - /// caller to ensure that this option is only used in conjuction with a - /// compiler which supports the `-stdlib` flag. - /// - /// A value of `None` indicates that no specific C++ standard library should - /// be used, otherwise `-stdlib` is added to the compile invocation. - /// - /// The given library name must not contain the `lib` prefix. - /// - /// Common values: - /// - `stdc++` for GNU - /// - `c++` for Clang - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .cpp_set_stdlib("c++") - /// .compile("libfoo.a"); - /// ``` - pub fn cpp_set_stdlib<'a, V: Into>>( - &mut self, - cpp_set_stdlib: V, - ) -> &mut Build { - let cpp_set_stdlib = cpp_set_stdlib.into(); - self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); - self.cpp_link_stdlib(cpp_set_stdlib); - self - } - - /// Configures the target this configuration will be compiling for. - /// - /// This option is automatically scraped from the `TARGET` environment - /// variable by build scripts, so it's not required to call this function. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .target("aarch64-linux-android") - /// .compile("foo"); - /// ``` - pub fn target(&mut self, target: &str) -> &mut Build { - self.target = Some(target.to_string()); - self - } - - /// Configures the host assumed by this configuration. - /// - /// This option is automatically scraped from the `HOST` environment - /// variable by build scripts, so it's not required to call this function. - /// - /// # Example - /// - /// ```no_run - /// cc::Build::new() - /// .file("src/foo.c") - /// .host("arm-linux-gnueabihf") - /// .compile("foo"); - /// ``` - pub fn host(&mut self, host: &str) -> &mut Build { - self.host = Some(host.to_string()); - self - } - - /// Configures the optimization level of the generated object files. - /// - /// This option is automatically scraped from the `OPT_LEVEL` environment - /// variable by build scripts, so it's not required to call this function. - pub fn opt_level(&mut self, opt_level: u32) -> &mut Build { - self.opt_level = Some(opt_level.to_string()); - self - } - - /// Configures the optimization level of the generated object files. - /// - /// This option is automatically scraped from the `OPT_LEVEL` environment - /// variable by build scripts, so it's not required to call this function. - pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Build { - self.opt_level = Some(opt_level.to_string()); - self - } - - /// Configures whether the compiler will emit debug information when - /// generating object files. - /// - /// This option is automatically scraped from the `DEBUG` environment - /// variable by build scripts, so it's not required to call this function. - pub fn debug(&mut self, debug: bool) -> &mut Build { - self.debug = Some(debug); - self - } - - /// Configures whether the compiler will emit instructions to store - /// frame pointers during codegen. - /// - /// This option is automatically enabled when debug information is emitted. - /// Otherwise the target platform compiler's default will be used. - /// You can use this option to force a specific setting. - pub fn force_frame_pointer(&mut self, force: bool) -> &mut Build { - self.force_frame_pointer = Some(force); - self - } - - /// Configures the output directory where all object files and static - /// libraries will be located. - /// - /// This option is automatically scraped from the `OUT_DIR` environment - /// variable by build scripts, so it's not required to call this function. - pub fn out_dir>(&mut self, out_dir: P) -> &mut Build { - self.out_dir = Some(out_dir.as_ref().to_owned()); - self - } - - /// Configures the compiler to be used to produce output. - /// - /// This option is automatically determined from the target platform or a - /// number of environment variables, so it's not required to call this - /// function. - pub fn compiler>(&mut self, compiler: P) -> &mut Build { - self.compiler = Some(compiler.as_ref().to_owned()); - self - } - - /// Configures the tool used to assemble archives. - /// - /// This option is automatically determined from the target platform or a - /// number of environment variables, so it's not required to call this - /// function. - pub fn archiver>(&mut self, archiver: P) -> &mut Build { - self.archiver = Some(archiver.as_ref().to_owned()); - self - } - /// Define whether metadata should be emitted for cargo allowing it to - /// automatically link the binary. Defaults to `true`. - /// - /// The emitted metadata is: - /// - /// - `rustc-link-lib=static=`*compiled lib* - /// - `rustc-link-search=native=`*target folder* - /// - When target is MSVC, the ATL-MFC libs are added via `rustc-link-search=native=` - /// - When C++ is enabled, the C++ stdlib is added via `rustc-link-lib` - /// - pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { - self.cargo_metadata = cargo_metadata; - self - } - - /// Configures whether the compiler will emit position independent code. - /// - /// This option defaults to `false` for `windows-gnu` and bare metal targets and - /// to `true` for all other targets. - pub fn pic(&mut self, pic: bool) -> &mut Build { - self.pic = Some(pic); - self - } - - /// Configures whether the Procedure Linkage Table is used for indirect - /// calls into shared libraries. - /// - /// The PLT is used to provide features like lazy binding, but introduces - /// a small performance loss due to extra pointer indirection. Setting - /// `use_plt` to `false` can provide a small performance increase. - /// - /// Note that skipping the PLT requires a recent version of GCC/Clang. - /// - /// This only applies to ELF targets. It has no effect on other platforms. - pub fn use_plt(&mut self, use_plt: bool) -> &mut Build { - self.use_plt = Some(use_plt); - self - } - - /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. - /// - /// This option defaults to `false`, and affect only msvc targets. - pub fn static_crt(&mut self, static_crt: bool) -> &mut Build { - self.static_crt = Some(static_crt); - self - } - - #[doc(hidden)] - pub fn __set_env(&mut self, a: A, b: B) -> &mut Build - where - A: AsRef, - B: AsRef, - { - self.env - .push((a.as_ref().to_owned(), b.as_ref().to_owned())); - self - } - - /// Run the compiler, generating the file `output` - /// - /// This will return a result instead of panicing; see compile() for the complete description. - pub fn try_compile(&self, output: &str) -> Result<(), Error> { - let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { - (&output[3..output.len() - 2], output.to_owned()) - } else { - let mut gnu = String::with_capacity(5 + output.len()); - gnu.push_str("lib"); - gnu.push_str(&output); - gnu.push_str(".a"); - (output, gnu) - }; - let dst = self.get_out_dir()?; - - let mut objects = Vec::new(); - for file in self.files.iter() { - let obj = dst.join(file).with_extension("o"); - let obj = if !obj.starts_with(&dst) { - dst.join(obj.file_name().ok_or_else(|| { - Error::new(ErrorKind::IOError, "Getting object file details failed.") - })?) - } else { - obj - }; - - match obj.parent() { - Some(s) => fs::create_dir_all(s)?, - None => { - return Err(Error::new( - ErrorKind::IOError, - "Getting object file details failed.", - )); - } - }; - - objects.push(Object::new(file.to_path_buf(), obj)); - } - self.compile_objects(&objects)?; - self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?; - - if self.get_target()?.contains("msvc") { - let compiler = self.get_base_compiler()?; - let atlmfc_lib = compiler - .env() - .iter() - .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) - .and_then(|&(_, ref lib_paths)| { - env::split_paths(lib_paths).find(|path| { - let sub = Path::new("atlmfc/lib"); - path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) - }) - }); - - if let Some(atlmfc_lib) = atlmfc_lib { - self.print(&format!( - "cargo:rustc-link-search=native={}", - atlmfc_lib.display() - )); - } - } - - self.print(&format!("cargo:rustc-link-lib=static={}", lib_name)); - self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); - - // Add specific C++ libraries, if enabled. - if self.cpp { - if let Some(stdlib) = self.get_cpp_link_stdlib()? { - self.print(&format!("cargo:rustc-link-lib={}", stdlib)); - } - } - - Ok(()) - } - - /// Run the compiler, generating the file `output` - /// - /// The name `output` should be the name of the library. For backwards compatibility, - /// the `output` may start with `lib` and end with `.a`. The Rust compilier will create - /// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix, - /// ending with `.lib`. - /// - /// # Panics - /// - /// Panics if `output` is not formatted correctly or if one of the underlying - /// compiler commands fails. It can also panic if it fails reading file names - /// or creating directories. - pub fn compile(&self, output: &str) { - if let Err(e) = self.try_compile(output) { - fail(&e.message); - } - } - - #[cfg(feature = "parallel")] - fn compile_objects<'me>(&'me self, objs: &[Object]) -> Result<(), Error> { - use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; - use std::sync::Once; - - // Limit our parallelism globally with a jobserver. Start off by - // releasing our own token for this process so we can have a bit of an - // easier to write loop below. If this fails, though, then we're likely - // on Windows with the main implicit token, so we just have a bit extra - // parallelism for a bit and don't reacquire later. - let server = jobserver(); - let reacquire = server.release_raw().is_ok(); - - // When compiling objects in parallel we do a few dirty tricks to speed - // things up: - // - // * First is that we use the `jobserver` crate to limit the parallelism - // of this build script. The `jobserver` crate will use a jobserver - // configured by Cargo for build scripts to ensure that parallelism is - // coordinated across C compilations and Rust compilations. Before we - // compile anything we make sure to wait until we acquire a token. - // - // Note that this jobserver is cached globally so we only used one per - // process and only worry about creating it once. - // - // * Next we use a raw `thread::spawn` per thread to actually compile - // objects in parallel. We only actually spawn a thread after we've - // acquired a token to perform some work - // - // * Finally though we want to keep the dependencies of this crate - // pretty light, so we avoid using a safe abstraction like `rayon` and - // instead rely on some bits of `unsafe` code. We know that this stack - // frame persists while everything is compiling so we use all the - // stack-allocated objects without cloning/reallocating. We use a - // transmute to `State` with a `'static` lifetime to persist - // everything we need across the boundary, and the join-on-drop - // semantics of `JoinOnDrop` should ensure that our stack frame is - // alive while threads are alive. - // - // With all that in mind we compile all objects in a loop here, after we - // acquire the appropriate tokens, Once all objects have been compiled - // we join on all the threads and propagate the results of compilation. - // - // Note that as a slight optimization we try to break out as soon as - // possible as soon as any compilation fails to ensure that errors get - // out to the user as fast as possible. - let error = AtomicBool::new(false); - let mut threads = Vec::new(); - for obj in objs { - if error.load(SeqCst) { - break; - } - let token = server.acquire()?; - let state = State { - build: self, - obj, - error: &error, - }; - let state = unsafe { std::mem::transmute::>(state) }; - let thread = thread::spawn(|| { - let state: State<'me> = state; // erase the `'static` lifetime - let result = state.build.compile_object(state.obj); - if result.is_err() { - state.error.store(true, SeqCst); - } - drop(token); // make sure our jobserver token is released after the compile - return result; - }); - threads.push(JoinOnDrop(Some(thread))); - } - - for mut thread in threads { - if let Some(thread) = thread.0.take() { - thread.join().expect("thread should not panic")?; - } - } - - // Reacquire our process's token before we proceed, which we released - // before entering the loop above. - if reacquire { - server.acquire_raw()?; - } - - return Ok(()); - - /// Shared state from the parent thread to the child thread. This - /// package of pointers is temporarily transmuted to a `'static` - /// lifetime to cross the thread boundary and then once the thread is - /// running we erase the `'static` to go back to an anonymous lifetime. - struct State<'a> { - build: &'a Build, - obj: &'a Object, - error: &'a AtomicBool, - } - - /// Returns a suitable `jobserver::Client` used to coordinate - /// parallelism between build scripts. - fn jobserver() -> &'static jobserver::Client { - static INIT: Once = Once::new(); - static mut JOBSERVER: Option = None; - - fn _assert_sync() {} - _assert_sync::(); - - unsafe { - INIT.call_once(|| { - let server = default_jobserver(); - JOBSERVER = Some(server); - }); - JOBSERVER.as_ref().unwrap() - } - } - - unsafe fn default_jobserver() -> jobserver::Client { - // Try to use the environmental jobserver which Cargo typically - // initializes for us... - if let Some(client) = jobserver::Client::from_env() { - return client; - } - - // ... but if that fails for whatever reason select something - // reasonable and crate a new jobserver. Use `NUM_JOBS` if set (it's - // configured by Cargo) and otherwise just fall back to a - // semi-reasonable number. Note that we could use `num_cpus` here - // but it's an extra dependency that will almost never be used, so - // it's generally not too worth it. - let mut parallelism = 4; - if let Ok(amt) = env::var("NUM_JOBS") { - if let Ok(amt) = amt.parse() { - parallelism = amt; - } - } - - // If we create our own jobserver then be sure to reserve one token - // for ourselves. - let client = jobserver::Client::new(parallelism).expect("failed to create jobserver"); - client.acquire_raw().expect("failed to acquire initial"); - return client; - } - - struct JoinOnDrop(Option>>); - - impl Drop for JoinOnDrop { - fn drop(&mut self) { - if let Some(thread) = self.0.take() { - drop(thread.join()); - } - } - } - } - - #[cfg(not(feature = "parallel"))] - fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { - for obj in objs { - self.compile_object(obj)?; - } - Ok(()) - } - - fn compile_object(&self, obj: &Object) -> Result<(), Error> { - let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm"); - let target = self.get_target()?; - let msvc = target.contains("msvc"); - let compiler = self.try_get_compiler()?; - let clang = compiler.family == ToolFamily::Clang; - let (mut cmd, name) = if msvc && is_asm { - self.msvc_macro_assembler()? - } else { - let mut cmd = compiler.to_command(); - for &(ref a, ref b) in self.env.iter() { - cmd.env(a, b); - } - ( - cmd, - compiler - .path - .file_name() - .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? - .to_string_lossy() - .into_owned(), - ) - }; - let is_arm = target.contains("aarch64") || target.contains("arm"); - command_add_output_file(&mut cmd, &obj.dst, self.cuda, msvc, clang, is_asm, is_arm); - // armasm and armasm64 don't requrie -c option - if !msvc || !is_asm || !is_arm { - cmd.arg("-c"); - } - cmd.arg(&obj.src); - - run(&mut cmd, &name)?; - Ok(()) - } - - /// This will return a result instead of panicing; see expand() for the complete description. - pub fn try_expand(&self) -> Result, Error> { - let compiler = self.try_get_compiler()?; - let mut cmd = compiler.to_command(); - for &(ref a, ref b) in self.env.iter() { - cmd.env(a, b); - } - cmd.arg("-E"); - - assert!( - self.files.len() <= 1, - "Expand may only be called for a single file" - ); - - for file in self.files.iter() { - cmd.arg(file); - } - - let name = compiler - .path - .file_name() - .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? - .to_string_lossy() - .into_owned(); - - Ok(run_output(&mut cmd, &name)?) - } - - /// Run the compiler, returning the macro-expanded version of the input files. - /// - /// This is only relevant for C and C++ files. - /// - /// # Panics - /// Panics if more than one file is present in the config, or if compiler - /// path has an invalid file name. - /// - /// # Example - /// ```no_run - /// let out = cc::Build::new().file("src/foo.c").expand(); - /// ``` - pub fn expand(&self) -> Vec { - match self.try_expand() { - Err(e) => fail(&e.message), - Ok(v) => v, - } - } - - /// Get the compiler that's in use for this configuration. - /// - /// This function will return a `Tool` which represents the culmination - /// of this configuration at a snapshot in time. The returned compiler can - /// be inspected (e.g. the path, arguments, environment) to forward along to - /// other tools, or the `to_command` method can be used to invoke the - /// compiler itself. - /// - /// This method will take into account all configuration such as debug - /// information, optimization level, include directories, defines, etc. - /// Additionally, the compiler binary in use follows the standard - /// conventions for this path, e.g. looking at the explicitly set compiler, - /// environment variables (a number of which are inspected here), and then - /// falling back to the default configuration. - /// - /// # Panics - /// - /// Panics if an error occurred while determining the architecture. - pub fn get_compiler(&self) -> Tool { - match self.try_get_compiler() { - Ok(tool) => tool, - Err(e) => fail(&e.message), - } - } - - /// Get the compiler that's in use for this configuration. - /// - /// This will return a result instead of panicing; see get_compiler() for the complete description. - pub fn try_get_compiler(&self) -> Result { - let opt_level = self.get_opt_level()?; - let target = self.get_target()?; - - let mut cmd = self.get_base_compiler()?; - let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }); - - // Disable default flag generation via `no_default_flags` or environment variable - let no_defaults = self.no_default_flags || self.getenv("CRATE_CC_NO_DEFAULTS").is_some(); - - if !no_defaults { - self.add_default_flags(&mut cmd, &target, &opt_level)?; - } else { - println!("Info: default compiler flags are disabled"); - } - - for arg in envflags { - cmd.push_cc_arg(arg.into()); - } - - for directory in self.include_directories.iter() { - cmd.args.push("-I".into()); - cmd.args.push(directory.into()); - } - - // If warnings and/or extra_warnings haven't been explicitly set, - // then we set them only if the environment doesn't already have - // CFLAGS/CXXFLAGS, since those variables presumably already contain - // the desired set of warnings flags. - - if self - .warnings - .unwrap_or(if self.has_flags() { false } else { true }) - { - let wflags = cmd.family.warnings_flags().into(); - cmd.push_cc_arg(wflags); - } - - if self - .extra_warnings - .unwrap_or(if self.has_flags() { false } else { true }) - { - if let Some(wflags) = cmd.family.extra_warnings_flags() { - cmd.push_cc_arg(wflags.into()); - } - } - - for flag in self.flags.iter() { - cmd.args.push(flag.into()); - } - - for flag in self.flags_supported.iter() { - if self.is_flag_supported(flag).unwrap_or(false) { - cmd.push_cc_arg(flag.into()); - } - } - - for &(ref key, ref value) in self.definitions.iter() { - if let Some(ref value) = *value { - cmd.args.push(format!("-D{}={}", key, value).into()); - } else { - cmd.args.push(format!("-D{}", key).into()); - } - } - - if self.warnings_into_errors { - let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); - cmd.push_cc_arg(warnings_to_errors_flag); - } - - Ok(cmd) - } - - fn add_default_flags( - &self, - cmd: &mut Tool, - target: &str, - opt_level: &str, - ) -> Result<(), Error> { - // Non-target flags - // If the flag is not conditioned on target variable, it belongs here :) - match cmd.family { - ToolFamily::Msvc { .. } => { - cmd.push_cc_arg("-nologo".into()); - - let crt_flag = match self.static_crt { - Some(true) => "-MT", - Some(false) => "-MD", - None => { - let features = self - .getenv("CARGO_CFG_TARGET_FEATURE") - .unwrap_or(String::new()); - if features.contains("crt-static") { - "-MT" - } else { - "-MD" - } - } - }; - cmd.push_cc_arg(crt_flag.into()); - - match &opt_level[..] { - // Msvc uses /O1 to enable all optimizations that minimize code size. - "z" | "s" | "1" => cmd.push_opt_unless_duplicate("-O1".into()), - // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. - "2" | "3" => cmd.push_opt_unless_duplicate("-O2".into()), - _ => {} - } - } - ToolFamily::Gnu | ToolFamily::Clang => { - // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does - // not support '-Oz' - if opt_level == "z" && cmd.family != ToolFamily::Clang { - cmd.push_opt_unless_duplicate("-Os".into()); - } else { - cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); - } - - if cmd.family == ToolFamily::Clang && target.contains("android") { - // For compatibility with code that doesn't use pre-defined `__ANDROID__` macro. - // If compiler used via ndk-build or cmake (officially supported build methods) - // this macros is defined. - // See https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/cmake/android.toolchain.cmake#456 - // https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/core/build-binary.mk#141 - cmd.push_opt_unless_duplicate("-DANDROID".into()); - } - - if !target.contains("-ios") { - cmd.push_cc_arg("-ffunction-sections".into()); - cmd.push_cc_arg("-fdata-sections".into()); - } - // Disable generation of PIC on bare-metal for now: rust-lld doesn't support this yet - if self - .pic - .unwrap_or(!target.contains("windows") && !target.contains("-none-")) - { - cmd.push_cc_arg("-fPIC".into()); - // PLT only applies if code is compiled with PIC support, - // and only for ELF targets. - if target.contains("linux") && !self.use_plt.unwrap_or(true) { - cmd.push_cc_arg("-fno-plt".into()); - } - } - } - } - - if self.get_debug() { - if self.cuda { - // NVCC debug flag - cmd.args.push("-G".into()); - } - let family = cmd.family; - family.add_debug_flags(cmd); - } - - if self.get_force_frame_pointer() { - let family = cmd.family; - family.add_force_frame_pointer(cmd); - } - - // Target flags - match cmd.family { - ToolFamily::Clang => { - if !(target.contains("android") - && android_clang_compiler_uses_target_arg_internally(&cmd.path)) - { - cmd.args.push(format!("--target={}", target).into()); - } - } - ToolFamily::Msvc { clang_cl } => { - // This is an undocumented flag from MSVC but helps with making - // builds more reproducible by avoiding putting timestamps into - // files. - cmd.args.push("-Brepro".into()); - - if clang_cl { - if target.contains("x86_64") { - cmd.args.push("-m64".into()); - } else if target.contains("86") { - cmd.args.push("-m32".into()); - cmd.push_cc_arg("-arch:IA32".into()); - } else { - cmd.push_cc_arg(format!("--target={}", target).into()); - } - } else { - if target.contains("i586") { - cmd.push_cc_arg("-arch:IA32".into()); - } - } - - // There is a check in corecrt.h that will generate a - // compilation error if - // _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE is - // not defined to 1. The check was added in Windows - // 8 days because only store apps were allowed on ARM. - // This changed with the release of Windows 10 IoT Core. - // The check will be going away in future versions of - // the SDK, but for all released versions of the - // Windows SDK it is required. - if target.contains("arm") || target.contains("thumb") { - cmd.args - .push("-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); - } - } - ToolFamily::Gnu => { - if target.contains("i686") || target.contains("i586") { - cmd.args.push("-m32".into()); - } else if target == "x86_64-unknown-linux-gnux32" { - cmd.args.push("-mx32".into()); - } else if target.contains("x86_64") || target.contains("powerpc64") { - cmd.args.push("-m64".into()); - } - - if self.static_flag.is_none() { - let features = self - .getenv("CARGO_CFG_TARGET_FEATURE") - .unwrap_or(String::new()); - if features.contains("crt-static") { - cmd.args.push("-static".into()); - } - } - - // armv7 targets get to use armv7 instructions - if (target.starts_with("armv7") || target.starts_with("thumbv7")) - && target.contains("-linux-") - { - cmd.args.push("-march=armv7-a".into()); - } - - // (x86 Android doesn't say "eabi") - if target.contains("-androideabi") && target.contains("v7") { - // -march=armv7-a handled above - cmd.args.push("-mthumb".into()); - if !target.contains("neon") { - // On android we can guarantee some extra float instructions - // (specified in the android spec online) - // NEON guarantees even more; see below. - cmd.args.push("-mfpu=vfpv3-d16".into()); - } - cmd.args.push("-mfloat-abi=softfp".into()); - } - - if target.contains("neon") { - cmd.args.push("-mfpu=neon-vfpv4".into()); - } - - if target.starts_with("armv4t-unknown-linux-") { - cmd.args.push("-march=armv4t".into()); - cmd.args.push("-marm".into()); - cmd.args.push("-mfloat-abi=soft".into()); - } - - if target.starts_with("armv5te-unknown-linux-") { - cmd.args.push("-march=armv5te".into()); - cmd.args.push("-marm".into()); - cmd.args.push("-mfloat-abi=soft".into()); - } - - // For us arm == armv6 by default - if target.starts_with("arm-unknown-linux-") { - cmd.args.push("-march=armv6".into()); - cmd.args.push("-marm".into()); - if target.ends_with("hf") { - cmd.args.push("-mfpu=vfp".into()); - } else { - cmd.args.push("-mfloat-abi=soft".into()); - } - } - - // We can guarantee some settings for FRC - if target.starts_with("arm-frc-") { - cmd.args.push("-march=armv7-a".into()); - cmd.args.push("-mcpu=cortex-a9".into()); - cmd.args.push("-mfpu=vfpv3".into()); - cmd.args.push("-mfloat-abi=softfp".into()); - cmd.args.push("-marm".into()); - } - - // Turn codegen down on i586 to avoid some instructions. - if target.starts_with("i586-unknown-linux-") { - cmd.args.push("-march=pentium".into()); - } - - // Set codegen level for i686 correctly - if target.starts_with("i686-unknown-linux-") { - cmd.args.push("-march=i686".into()); - } - - // Looks like `musl-gcc` makes is hard for `-m32` to make its way - // all the way to the linker, so we need to actually instruct the - // linker that we're generating 32-bit executables as well. This'll - // typically only be used for build scripts which transitively use - // these flags that try to compile executables. - if target == "i686-unknown-linux-musl" || target == "i586-unknown-linux-musl" { - cmd.args.push("-Wl,-melf_i386".into()); - } - - if target.starts_with("thumb") { - cmd.args.push("-mthumb".into()); - - if target.ends_with("eabihf") { - cmd.args.push("-mfloat-abi=hard".into()) - } - } - if target.starts_with("thumbv6m") { - cmd.args.push("-march=armv6s-m".into()); - } - if target.starts_with("thumbv7em") { - cmd.args.push("-march=armv7e-m".into()); - - if target.ends_with("eabihf") { - cmd.args.push("-mfpu=fpv4-sp-d16".into()) - } - } - if target.starts_with("thumbv7m") { - cmd.args.push("-march=armv7-m".into()); - } - if target.starts_with("thumbv8m.base") { - cmd.args.push("-march=armv8-m.base".into()); - } - if target.starts_with("thumbv8m.main") { - cmd.args.push("-march=armv8-m.main".into()); - - if target.ends_with("eabihf") { - cmd.args.push("-mfpu=fpv5-sp-d16".into()) - } - } - if target.starts_with("armebv7r") | target.starts_with("armv7r") { - if target.starts_with("armeb") { - cmd.args.push("-mbig-endian".into()); - } else { - cmd.args.push("-mlittle-endian".into()); - } - - // ARM mode - cmd.args.push("-marm".into()); - - // R Profile - cmd.args.push("-march=armv7-r".into()); - - if target.ends_with("eabihf") { - // Calling convention - cmd.args.push("-mfloat-abi=hard".into()); - - // lowest common denominator FPU - // (see Cortex-R4 technical reference manual) - cmd.args.push("-mfpu=vfpv3-d16".into()) - } else { - // Calling convention - cmd.args.push("-mfloat-abi=soft".into()); - } - } - if target.starts_with("armv7a") { - cmd.args.push("-march=armv7-a".into()); - - if target.ends_with("eabihf") { - // lowest common denominator FPU - cmd.args.push("-mfpu=vfpv3-d16".into()); - } - } - if target.starts_with("riscv32") || target.starts_with("riscv64") { - // get the 32i/32imac/32imc/64gc/64imac/... part - let mut parts = target.split('-'); - if let Some(arch) = parts.next() { - let arch = &arch[5..]; - cmd.args.push(("-march=rv".to_owned() + arch).into()); - if target.contains("linux") && arch.starts_with("64") { - cmd.args.push("-mabi=lp64d".into()); - } else if target.contains("linux") && arch.starts_with("32") { - cmd.args.push("-mabi=ilp32d".into()); - } else if arch.starts_with("64") { - cmd.args.push("-mabi=lp64".into()); - } else { - cmd.args.push("-mabi=ilp32".into()); - } - cmd.args.push("-mcmodel=medany".into()); - } - } - } - } - - if target.contains("-ios") { - // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be - // detected instead. - self.ios_flags(cmd)?; - } - - if self.static_flag.unwrap_or(false) { - cmd.args.push("-static".into()); - } - if self.shared_flag.unwrap_or(false) { - cmd.args.push("-shared".into()); - } - - if self.cpp { - match (self.cpp_set_stdlib.as_ref(), cmd.family) { - (None, _) => {} - (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => { - cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); - } - _ => { - println!( - "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ - does not support this option, ignored", - cmd.family - ); - } - } - } - - Ok(()) - } - - fn has_flags(&self) -> bool { - let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; - let flags_env_var_value = self.get_var(flags_env_var_name); - if let Ok(_) = flags_env_var_value { - true - } else { - false - } - } - - fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { - let target = self.get_target()?; - let tool = if target.contains("x86_64") { - "ml64.exe" - } else if target.contains("arm") { - "armasm.exe" - } else if target.contains("aarch64") { - "armasm64.exe" - } else { - "ml.exe" - }; - let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); - for directory in self.include_directories.iter() { - cmd.arg("-I").arg(directory); - } - for &(ref key, ref value) in self.definitions.iter() { - if let Some(ref value) = *value { - cmd.arg(&format!("-D{}={}", key, value)); - } else { - cmd.arg(&format!("-D{}", key)); - } - } - - if target.contains("i686") || target.contains("i586") { - cmd.arg("-safeseh"); - } - for flag in self.flags.iter() { - cmd.arg(flag); - } - - Ok((cmd, tool.to_string())) - } - - fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> { - // Delete the destination if it exists as the `ar` tool at least on Unix - // appends to it, which we don't want. - let _ = fs::remove_file(&dst); - - let objects: Vec<_> = objs.iter().map(|obj| obj.dst.clone()).collect(); - let target = self.get_target()?; - if target.contains("msvc") { - let (mut cmd, program) = self.get_ar()?; - let mut out = OsString::from("-out:"); - out.push(dst); - cmd.arg(out).arg("-nologo"); - for flag in self.ar_flags.iter() { - cmd.arg(flag); - } - - // Similar to https://github.com/rust-lang/rust/pull/47507 - // and https://github.com/rust-lang/rust/pull/48548 - let estimated_command_line_len = objects - .iter() - .chain(&self.objects) - .map(|a| a.as_os_str().len()) - .sum::(); - if estimated_command_line_len > 1024 * 6 { - let mut args = String::from("\u{FEFF}"); // BOM - for arg in objects.iter().chain(&self.objects) { - args.push('"'); - for c in arg.to_str().unwrap().chars() { - if c == '"' { - args.push('\\') - } - args.push(c) - } - args.push('"'); - args.push('\n'); - } - - let mut utf16le = Vec::new(); - for code_unit in args.encode_utf16() { - utf16le.push(code_unit as u8); - utf16le.push((code_unit >> 8) as u8); - } - - let mut args_file = OsString::from(dst); - args_file.push(".args"); - fs::File::create(&args_file) - .unwrap() - .write_all(&utf16le) - .unwrap(); - - let mut args_file_arg = OsString::from("@"); - args_file_arg.push(args_file); - cmd.arg(args_file_arg); - } else { - cmd.args(&objects).args(&self.objects); - } - run(&mut cmd, &program)?; - - // The Rust compiler will look for libfoo.a and foo.lib, but the - // MSVC linker will also be passed foo.lib, so be sure that both - // exist for now. - let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); - let _ = fs::remove_file(&lib_dst); - match fs::hard_link(&dst, &lib_dst).or_else(|_| { - // if hard-link fails, just copy (ignoring the number of bytes written) - fs::copy(&dst, &lib_dst).map(|_| ()) - }) { - Ok(_) => (), - Err(_) => { - return Err(Error::new( - ErrorKind::IOError, - "Could not copy or create a hard-link to the generated lib file.", - )); - } - }; - } else { - let (mut ar, cmd) = self.get_ar()?; - - // Set an environment variable to tell the OSX archiver to ensure - // that all dates listed in the archive are zero, improving - // determinism of builds. AFAIK there's not really official - // documentation of this but there's a lot of references to it if - // you search google. - // - // You can reproduce this locally on a mac with: - // - // $ touch foo.c - // $ cc -c foo.c -o foo.o - // - // # Notice that these two checksums are different - // $ ar crus libfoo1.a foo.o && sleep 2 && ar crus libfoo2.a foo.o - // $ md5sum libfoo*.a - // - // # Notice that these two checksums are the same - // $ export ZERO_AR_DATE=1 - // $ ar crus libfoo1.a foo.o && sleep 2 && touch foo.o && ar crus libfoo2.a foo.o - // $ md5sum libfoo*.a - // - // In any case if this doesn't end up getting read, it shouldn't - // cause that many issues! - ar.env("ZERO_AR_DATE", "1"); - for flag in self.ar_flags.iter() { - ar.arg(flag); - } - run( - ar.arg("crs").arg(dst).args(&objects).args(&self.objects), - &cmd, - )?; - } - - Ok(()) - } - - fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> { - enum ArchSpec { - Device(&'static str), - Simulator(&'static str), - } - - let target = self.get_target()?; - let arch = target.split('-').nth(0).ok_or_else(|| { - Error::new( - ErrorKind::ArchitectureInvalid, - "Unknown architecture for iOS target.", - ) - })?; - let arch = match arch { - "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), - "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), - "arm64" | "aarch64" => ArchSpec::Device("arm64"), - "i386" | "i686" => ArchSpec::Simulator("-m32"), - "x86_64" => ArchSpec::Simulator("-m64"), - _ => { - return Err(Error::new( - ErrorKind::ArchitectureInvalid, - "Unknown architecture for iOS target.", - )); - } - }; - - let min_version = - std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into()); - - let sdk = match arch { - ArchSpec::Device(arch) => { - cmd.args.push("-arch".into()); - cmd.args.push(arch.into()); - cmd.args - .push(format!("-miphoneos-version-min={}", min_version).into()); - "iphoneos" - } - ArchSpec::Simulator(arch) => { - cmd.args.push(arch.into()); - cmd.args - .push(format!("-mios-simulator-version-min={}", min_version).into()); - "iphonesimulator" - } - }; - - self.print(&format!("Detecting iOS SDK path for {}", sdk)); - let sdk_path = self - .cmd("xcrun") - .arg("--show-sdk-path") - .arg("--sdk") - .arg(sdk) - .stderr(Stdio::inherit()) - .output()? - .stdout; - - let sdk_path = match String::from_utf8(sdk_path) { - Ok(p) => p, - Err(_) => { - return Err(Error::new( - ErrorKind::IOError, - "Unable to determine iOS SDK path.", - )); - } - }; - - cmd.args.push("-isysroot".into()); - cmd.args.push(sdk_path.trim().into()); - cmd.args.push("-fembed-bitcode".into()); - /* - * TODO we probably ultimately want the -fembed-bitcode-marker flag - * but can't have it now because of an issue in LLVM: - * https://github.com/alexcrichton/cc-rs/issues/301 - * https://github.com/rust-lang/rust/pull/48896#comment-372192660 - */ - /* - if self.get_opt_level()? == "0" { - cmd.args.push("-fembed-bitcode-marker".into()); - } - */ - - Ok(()) - } - - fn cmd>(&self, prog: P) -> Command { - let mut cmd = Command::new(prog); - for &(ref a, ref b) in self.env.iter() { - cmd.env(a, b); - } - cmd - } - - fn get_base_compiler(&self) -> Result { - if let Some(ref c) = self.compiler { - return Ok(Tool::new(c.clone())); - } - let host = self.get_host()?; - let target = self.get_target()?; - let (env, msvc, gnu, traditional, clang) = if self.cpp { - ("CXX", "cl.exe", "g++", "c++", "clang++") - } else { - ("CC", "cl.exe", "gcc", "cc", "clang") - }; - - // On historical Solaris systems, "cc" may have been Sun Studio, which - // is not flag-compatible with "gcc". This history casts a long shadow, - // and many modern illumos distributions today ship GCC as "gcc" without - // also making it available as "cc". - let default = if host.contains("solaris") || host.contains("illumos") { - gnu - } else { - traditional - }; - - let cl_exe = windows_registry::find_tool(&target, "cl.exe"); - - let tool_opt: Option = self - .env_tool(env) - .map(|(tool, wrapper, args)| { - // find the driver mode, if any - const DRIVER_MODE: &str = "--driver-mode="; - let driver_mode = args - .iter() - .find(|a| a.starts_with(DRIVER_MODE)) - .map(|a| &a[DRIVER_MODE.len()..]); - // Chop off leading/trailing whitespace to work around - // semi-buggy build scripts which are shared in - // makefiles/configure scripts (where spaces are far more - // lenient) - let mut t = Tool::with_clang_driver(PathBuf::from(tool.trim()), driver_mode); - if let Some(cc_wrapper) = wrapper { - t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); - } - for arg in args { - t.cc_wrapper_args.push(arg.into()); - } - t - }) - .or_else(|| { - if target.contains("emscripten") { - let tool = if self.cpp { "em++" } else { "emcc" }; - // Windows uses bat file so we have to be a bit more specific - if cfg!(windows) { - let mut t = Tool::new(PathBuf::from("cmd")); - t.args.push("/c".into()); - t.args.push(format!("{}.bat", tool).into()); - Some(t) - } else { - Some(Tool::new(PathBuf::from(tool))) - } - } else { - None - } - }) - .or_else(|| cl_exe.clone()); - - let tool = match tool_opt { - Some(t) => t, - None => { - let compiler = if host.contains("windows") && target.contains("windows") { - if target.contains("msvc") { - msvc.to_string() - } else { - format!("{}.exe", gnu) - } - } else if target.contains("android") { - autodetect_android_compiler(&target, &host, gnu, clang) - } else if target.contains("cloudabi") { - format!("{}-{}", target, traditional) - } else if target == "wasm32-wasi" - || target == "wasm32-unknown-wasi" - || target == "wasm32-unknown-unknown" - { - "clang".to_string() - } else if target.contains("vxworks") { - "wr-c++".to_string() - } else if self.get_host()? != target { - let prefix = self.prefix_for_target(&target); - match prefix { - Some(prefix) => format!("{}-{}", prefix, gnu), - None => default.to_string(), - } - } else { - default.to_string() - }; - - let mut t = Tool::new(PathBuf::from(compiler)); - if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { - t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); - } - t - } - }; - - let mut tool = if self.cuda { - assert!( - tool.args.is_empty(), - "CUDA compilation currently assumes empty pre-existing args" - ); - let nvcc = match self.get_var("NVCC") { - Err(_) => "nvcc".into(), - Ok(nvcc) => nvcc, - }; - let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), None, self.cuda); - nvcc_tool - .args - .push(format!("-ccbin={}", tool.path.display()).into()); - nvcc_tool.family = tool.family; - nvcc_tool - } else { - tool - }; - - // If we found `cl.exe` in our environment, the tool we're returning is - // an MSVC-like tool, *and* no env vars were set then set env vars for - // the tool that we're returning. - // - // Env vars are needed for things like `link.exe` being put into PATH as - // well as header include paths sometimes. These paths are automatically - // included by default but if the `CC` or `CXX` env vars are set these - // won't be used. This'll ensure that when the env vars are used to - // configure for invocations like `clang-cl` we still get a "works out - // of the box" experience. - if let Some(cl_exe) = cl_exe { - if tool.family == (ToolFamily::Msvc { clang_cl: true }) - && tool.env.len() == 0 - && target.contains("msvc") - { - for &(ref k, ref v) in cl_exe.env.iter() { - tool.env.push((k.to_owned(), v.to_owned())); - } - } - } - - Ok(tool) - } - - fn get_var(&self, var_base: &str) -> Result { - let target = self.get_target()?; - let host = self.get_host()?; - let kind = if host == target { "HOST" } else { "TARGET" }; - let target_u = target.replace("-", "_"); - let res = self - .getenv(&format!("{}_{}", var_base, target)) - .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) - .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) - .or_else(|| self.getenv(var_base)); - - match res { - Some(res) => Ok(res), - None => Err(Error::new( - ErrorKind::EnvVarNotFound, - &format!("Could not find environment variable {}.", var_base), - )), - } - } - - fn envflags(&self, name: &str) -> Vec { - self.get_var(name) - .unwrap_or(String::new()) - .split(|c: char| c.is_whitespace()) - .filter(|s| !s.is_empty()) - .map(|s| s.to_string()) - .collect() - } - - /// Returns a fallback `cc_compiler_wrapper` by introspecting `RUSTC_WRAPPER` - fn rustc_wrapper_fallback() -> Option { - // No explicit CC wrapper was detected, but check if RUSTC_WRAPPER - // is defined and is a build accelerator that is compatible with - // C/C++ compilers (e.g. sccache) - let valid_wrappers = ["sccache"]; - - let rustc_wrapper = std::env::var_os("RUSTC_WRAPPER")?; - let wrapper_path = Path::new(&rustc_wrapper); - let wrapper_stem = wrapper_path.file_stem()?; - - if valid_wrappers.contains(&wrapper_stem.to_str()?) { - Some(rustc_wrapper.to_str()?.to_owned()) - } else { - None - } - } - - /// Returns compiler path, optional modifier name from whitelist, and arguments vec - fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { - let tool = match self.get_var(name) { - Ok(tool) => tool, - Err(_) => return None, - }; - - // If this is an exact path on the filesystem we don't want to do any - // interpretation at all, just pass it on through. This'll hopefully get - // us to support spaces-in-paths. - if Path::new(&tool).exists() { - return Some((tool, None, Vec::new())); - } - - // Ok now we want to handle a couple of scenarios. We'll assume from - // here on out that spaces are splitting separate arguments. Two major - // features we want to support are: - // - // CC='sccache cc' - // - // aka using `sccache` or any other wrapper/caching-like-thing for - // compilations. We want to know what the actual compiler is still, - // though, because our `Tool` API support introspection of it to see - // what compiler is in use. - // - // additionally we want to support - // - // CC='cc -flag' - // - // where the CC env var is used to also pass default flags to the C - // compiler. - // - // It's true that everything here is a bit of a pain, but apparently if - // you're not literally make or bash then you get a lot of bug reports. - let known_wrappers = ["ccache", "distcc", "sccache", "icecc"]; - - let mut parts = tool.split_whitespace(); - let maybe_wrapper = match parts.next() { - Some(s) => s, - None => return None, - }; - - let file_stem = Path::new(maybe_wrapper) - .file_stem() - .unwrap() - .to_str() - .unwrap(); - if known_wrappers.contains(&file_stem) { - if let Some(compiler) = parts.next() { - return Some(( - compiler.to_string(), - Some(maybe_wrapper.to_string()), - parts.map(|s| s.to_string()).collect(), - )); - } - } - - Some(( - maybe_wrapper.to_string(), - Self::rustc_wrapper_fallback(), - parts.map(|s| s.to_string()).collect(), - )) - } - - /// Returns the default C++ standard library for the current target: `libc++` - /// for OS X and `libstdc++` for anything else. - fn get_cpp_link_stdlib(&self) -> Result, Error> { - match self.cpp_link_stdlib.clone() { - Some(s) => Ok(s), - None => { - if let Ok(stdlib) = self.get_var("CXXSTDLIB") { - if stdlib.is_empty() { - Ok(None) - } else { - Ok(Some(stdlib)) - } - } else { - let target = self.get_target()?; - if target.contains("msvc") { - Ok(None) - } else if target.contains("apple") { - Ok(Some("c++".to_string())) - } else if target.contains("freebsd") { - Ok(Some("c++".to_string())) - } else if target.contains("openbsd") { - Ok(Some("c++".to_string())) - } else { - Ok(Some("stdc++".to_string())) - } - } - } - } - } - - fn get_ar(&self) -> Result<(Command, String), Error> { - if let Some(ref p) = self.archiver { - let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); - return Ok((self.cmd(p), name.to_string())); - } - if let Ok(p) = self.get_var("AR") { - return Ok((self.cmd(&p), p)); - } - let target = self.get_target()?; - let default_ar = "ar".to_string(); - let program = if target.contains("android") { - format!("{}-ar", target.replace("armv7", "arm")) - } else if target.contains("emscripten") { - // Windows use bat files so we have to be a bit more specific - if cfg!(windows) { - let mut cmd = self.cmd("cmd"); - cmd.arg("/c").arg("emar.bat"); - return Ok((cmd, "emar.bat".to_string())); - } - - "emar".to_string() - } else if target.contains("msvc") { - match windows_registry::find(&target, "lib.exe") { - Some(t) => return Ok((t, "lib.exe".to_string())), - None => "lib.exe".to_string(), - } - } else if self.get_host()? != target { - match self.prefix_for_target(&target) { - Some(p) => { - let target_ar = format!("{}-ar", p); - if Command::new(&target_ar).output().is_ok() { - target_ar - } else { - default_ar - } - } - None => default_ar, - } - } else { - default_ar - }; - Ok((self.cmd(&program), program)) - } - - fn prefix_for_target(&self, target: &str) -> Option { - // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" - let cc_env = self.getenv("CROSS_COMPILE"); - let cross_compile = cc_env - .as_ref() - .map(|s| s.trim_right_matches('-').to_owned()); - cross_compile.or(match &target[..] { - "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), - "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), - "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), - "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), - "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"), - "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), - "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), - "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), - "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), - "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), - "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), - "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), - "i586-unknown-linux-musl" => Some("musl"), - "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), - "i686-uwp-windows-gnu" => Some("i686-w64-mingw32"), - "i686-unknown-linux-musl" => Some("musl"), - "i686-unknown-netbsd" => Some("i486--netbsdelf"), - "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), - "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), - "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), - "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), - "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), - "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), - "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), - "mipsisa64r6el-unknown-linux-gnuabi64" => Some("mipsisa64r6el-linux-gnuabi64"), - "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), - "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), - "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), - "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), - "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), - "riscv32i-unknown-none-elf" => Some("riscv32-unknown-elf"), - "riscv32imac-unknown-none-elf" => Some("riscv32-unknown-elf"), - "riscv32imc-unknown-none-elf" => Some("riscv32-unknown-elf"), - "riscv64gc-unknown-none-elf" => Some("riscv64-unknown-elf"), - "riscv64imac-unknown-none-elf" => Some("riscv64-unknown-elf"), - "riscv64gc-unknown-linux-gnu" => Some("riscv64-linux-gnu"), - "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), - "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), - "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), - "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), - "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), - "armv7a-none-eabi" => Some("arm-none-eabi"), - "armv7a-none-eabihf" => Some("arm-none-eabi"), - "armebv7r-none-eabi" => Some("arm-none-eabi"), - "armebv7r-none-eabihf" => Some("arm-none-eabi"), - "armv7r-none-eabi" => Some("arm-none-eabi"), - "armv7r-none-eabihf" => Some("arm-none-eabi"), - "thumbv6m-none-eabi" => Some("arm-none-eabi"), - "thumbv7em-none-eabi" => Some("arm-none-eabi"), - "thumbv7em-none-eabihf" => Some("arm-none-eabi"), - "thumbv7m-none-eabi" => Some("arm-none-eabi"), - "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), - "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), - "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), - "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), - "x86_64-uwp-windows-gnu" => Some("x86_64-w64-mingw32"), - "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), - "x86_64-unknown-linux-musl" => Some("musl"), - "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), - _ => None, - } - .map(|x| x.to_owned())) - } - - fn get_target(&self) -> Result { - match self.target.clone() { - Some(t) => Ok(t), - None => Ok(self.getenv_unwrap("TARGET")?), - } - } - - fn get_host(&self) -> Result { - match self.host.clone() { - Some(h) => Ok(h), - None => Ok(self.getenv_unwrap("HOST")?), - } - } - - fn get_opt_level(&self) -> Result { - match self.opt_level.as_ref().cloned() { - Some(ol) => Ok(ol), - None => Ok(self.getenv_unwrap("OPT_LEVEL")?), - } - } - - fn get_debug(&self) -> bool { - self.debug.unwrap_or_else(|| match self.getenv("DEBUG") { - Some(s) => s != "false", - None => false, - }) - } - - fn get_force_frame_pointer(&self) -> bool { - self.force_frame_pointer.unwrap_or_else(|| self.get_debug()) - } - - fn get_out_dir(&self) -> Result { - match self.out_dir.clone() { - Some(p) => Ok(p), - None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| { - Error::new( - ErrorKind::EnvVarNotFound, - "Environment variable OUT_DIR not defined.", - ) - })?), - } - } - - fn getenv(&self, v: &str) -> Option { - let mut cache = self.env_cache.lock().unwrap(); - if let Some(val) = cache.get(v) { - return val.clone(); - } - let r = env::var(v).ok(); - self.print(&format!("{} = {:?}", v, r)); - cache.insert(v.to_string(), r.clone()); - r - } - - fn getenv_unwrap(&self, v: &str) -> Result { - match self.getenv(v) { - Some(s) => Ok(s), - None => Err(Error::new( - ErrorKind::EnvVarNotFound, - &format!("Environment variable {} not defined.", v.to_string()), - )), - } - } - - fn print(&self, s: &str) { - if self.cargo_metadata { - println!("{}", s); - } - } -} - -impl Default for Build { - fn default() -> Build { - Build::new() - } -} - -impl Tool { - fn new(path: PathBuf) -> Self { - Tool::with_features(path, None, false) - } - - fn with_clang_driver(path: PathBuf, clang_driver: Option<&str>) -> Self { - Self::with_features(path, clang_driver, false) - } - - #[cfg(windows)] - /// Explictly set the `ToolFamily`, skipping name-based detection. - fn with_family(path: PathBuf, family: ToolFamily) -> Self { - Self { - path: path, - cc_wrapper_path: None, - cc_wrapper_args: Vec::new(), - args: Vec::new(), - env: Vec::new(), - family: family, - cuda: false, - removed_args: Vec::new(), - } - } - - fn with_features(path: PathBuf, clang_driver: Option<&str>, cuda: bool) -> Self { - // Try to detect family of the tool from its name, falling back to Gnu. - let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { - if fname.contains("clang-cl") { - ToolFamily::Msvc { clang_cl: true } - } else if fname.contains("cl") - && !fname.contains("cloudabi") - && !fname.contains("uclibc") - && !fname.contains("clang") - { - ToolFamily::Msvc { clang_cl: false } - } else if fname.contains("clang") { - match clang_driver { - Some("cl") => ToolFamily::Msvc { clang_cl: true }, - _ => ToolFamily::Clang, - } - } else { - ToolFamily::Gnu - } - } else { - ToolFamily::Gnu - }; - - Tool { - path: path, - cc_wrapper_path: None, - cc_wrapper_args: Vec::new(), - args: Vec::new(), - env: Vec::new(), - family: family, - cuda: cuda, - removed_args: Vec::new(), - } - } - - /// Add an argument to be stripped from the final command arguments. - fn remove_arg(&mut self, flag: OsString) { - self.removed_args.push(flag); - } - - /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler". - /// - /// Currently this is only used for compiling CUDA sources, since NVCC only - /// accepts a limited set of GNU-like flags, and the rest must be prefixed - /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. - fn push_cc_arg(&mut self, flag: OsString) { - if self.cuda { - self.args.push("-Xcompiler".into()); - } - self.args.push(flag); - } - - fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool { - let flag = flag.to_str().unwrap(); - let mut chars = flag.chars(); - - // Only duplicate check compiler flags - if self.is_like_msvc() { - if chars.next() != Some('/') { - return false; - } - } else if self.is_like_gnu() || self.is_like_clang() { - if chars.next() != Some('-') { - return false; - } - } - - // Check for existing optimization flags (-O, /O) - if chars.next() == Some('O') { - return self - .args() - .iter() - .any(|ref a| a.to_str().unwrap_or("").chars().nth(1) == Some('O')); - } - - // TODO Check for existing -m..., -m...=..., /arch:... flags - return false; - } - - /// Don't push optimization arg if it conflicts with existing args - fn push_opt_unless_duplicate(&mut self, flag: OsString) { - if self.is_duplicate_opt_arg(&flag) { - println!("Info: Ignoring duplicate arg {:?}", &flag); - } else { - self.push_cc_arg(flag); - } - } - - /// Converts this compiler into a `Command` that's ready to be run. - /// - /// This is useful for when the compiler needs to be executed and the - /// command returned will already have the initial arguments and environment - /// variables configured. - pub fn to_command(&self) -> Command { - let mut cmd = match self.cc_wrapper_path { - Some(ref cc_wrapper_path) => { - let mut cmd = Command::new(&cc_wrapper_path); - cmd.arg(&self.path); - cmd - } - None => Command::new(&self.path), - }; - cmd.args(&self.cc_wrapper_args); - - let value = self - .args - .iter() - .filter(|a| !self.removed_args.contains(a)) - .collect::>(); - cmd.args(&value); - - for &(ref k, ref v) in self.env.iter() { - cmd.env(k, v); - } - cmd - } - - /// Returns the path for this compiler. - /// - /// Note that this may not be a path to a file on the filesystem, e.g. "cc", - /// but rather something which will be resolved when a process is spawned. - pub fn path(&self) -> &Path { - &self.path - } - - /// Returns the default set of arguments to the compiler needed to produce - /// executables for the target this compiler generates. - pub fn args(&self) -> &[OsString] { - &self.args - } - - /// Returns the set of environment variables needed for this compiler to - /// operate. - /// - /// This is typically only used for MSVC compilers currently. - pub fn env(&self) -> &[(OsString, OsString)] { - &self.env - } - - /// Returns the compiler command in format of CC environment variable. - /// Or empty string if CC env was not present - /// - /// This is typically used by configure script - pub fn cc_env(&self) -> OsString { - match self.cc_wrapper_path { - Some(ref cc_wrapper_path) => { - let mut cc_env = cc_wrapper_path.as_os_str().to_owned(); - cc_env.push(" "); - cc_env.push(self.path.to_path_buf().into_os_string()); - for arg in self.cc_wrapper_args.iter() { - cc_env.push(" "); - cc_env.push(arg); - } - cc_env - } - None => OsString::from(""), - } - } - - /// Returns the compiler flags in format of CFLAGS environment variable. - /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS - /// This is typically used by configure script - pub fn cflags_env(&self) -> OsString { - let mut flags = OsString::new(); - for (i, arg) in self.args.iter().enumerate() { - if i > 0 { - flags.push(" "); - } - flags.push(arg); - } - flags - } - - /// Whether the tool is GNU Compiler Collection-like. - pub fn is_like_gnu(&self) -> bool { - self.family == ToolFamily::Gnu - } - - /// Whether the tool is Clang-like. - pub fn is_like_clang(&self) -> bool { - self.family == ToolFamily::Clang - } - - /// Whether the tool is MSVC-like. - pub fn is_like_msvc(&self) -> bool { - match self.family { - ToolFamily::Msvc { .. } => true, - _ => false, - } - } -} - -fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { - let (mut child, print) = spawn(cmd, program)?; - let status = match child.wait() { - Ok(s) => s, - Err(_) => { - return Err(Error::new( - ErrorKind::ToolExecError, - &format!( - "Failed to wait on spawned child process, command {:?} with args {:?}.", - cmd, program - ), - )); - } - }; - print.join().unwrap(); - println!("{}", status); - - if status.success() { - Ok(()) - } else { - Err(Error::new( - ErrorKind::ToolExecError, - &format!( - "Command {:?} with args {:?} did not execute successfully (status code {}).", - cmd, program, status - ), - )) - } -} - -fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { - cmd.stdout(Stdio::piped()); - let (mut child, print) = spawn(cmd, program)?; - let mut stdout = vec![]; - child - .stdout - .take() - .unwrap() - .read_to_end(&mut stdout) - .unwrap(); - let status = match child.wait() { - Ok(s) => s, - Err(_) => { - return Err(Error::new( - ErrorKind::ToolExecError, - &format!( - "Failed to wait on spawned child process, command {:?} with args {:?}.", - cmd, program - ), - )); - } - }; - print.join().unwrap(); - println!("{}", status); - - if status.success() { - Ok(stdout) - } else { - Err(Error::new( - ErrorKind::ToolExecError, - &format!( - "Command {:?} with args {:?} did not execute successfully (status code {}).", - cmd, program, status - ), - )) - } -} - -fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Error> { - println!("running: {:?}", cmd); - - // Capture the standard error coming from these programs, and write it out - // with cargo:warning= prefixes. Note that this is a bit wonky to avoid - // requiring the output to be UTF-8, we instead just ship bytes from one - // location to another. - match cmd.stderr(Stdio::piped()).spawn() { - Ok(mut child) => { - let stderr = BufReader::new(child.stderr.take().unwrap()); - let print = thread::spawn(move || { - for line in stderr.split(b'\n').filter_map(|l| l.ok()) { - print!("cargo:warning="); - std::io::stdout().write_all(&line).unwrap(); - println!(""); - } - }); - Ok((child, print)) - } - Err(ref e) if e.kind() == io::ErrorKind::NotFound => { - let extra = if cfg!(windows) { - " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \ - for help)" - } else { - "" - }; - Err(Error::new( - ErrorKind::ToolNotFound, - &format!("Failed to find tool. Is `{}` installed?{}", program, extra), - )) - } - Err(_) => Err(Error::new( - ErrorKind::ToolExecError, - &format!("Command {:?} with args {:?} failed to start.", cmd, program), - )), - } -} - -fn fail(s: &str) -> ! { - let _ = writeln!(io::stderr(), "\n\nerror occurred: {}\n\n", s); - std::process::exit(1); -} - -fn command_add_output_file( - cmd: &mut Command, - dst: &Path, - cuda: bool, - msvc: bool, - clang: bool, - is_asm: bool, - is_arm: bool, -) { - if msvc && !clang && !cuda && !(is_asm && is_arm) { - let mut s = OsString::from("-Fo"); - s.push(&dst); - cmd.arg(s); - } else { - cmd.arg("-o").arg(&dst); - } -} - -// Use by default minimum available API level -// See note about naming here -// https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md#Clang -static NEW_STANDALONE_ANDROID_COMPILERS: [&str; 4] = [ - "aarch64-linux-android21-clang", - "armv7a-linux-androideabi16-clang", - "i686-linux-android16-clang", - "x86_64-linux-android21-clang", -]; - -// New "standalone" C/C++ cross-compiler executables from recent Android NDK -// are just shell scripts that call main clang binary (from Android NDK) with -// proper `--target` argument. -// -// For example, armv7a-linux-androideabi16-clang passes -// `--target=armv7a-linux-androideabi16` to clang. -// So to construct proper command line check if -// `--target` argument would be passed or not to clang -fn android_clang_compiler_uses_target_arg_internally(clang_path: &Path) -> bool { - NEW_STANDALONE_ANDROID_COMPILERS.iter().any(|x| { - let x: &OsStr = x.as_ref(); - x == clang_path.as_os_str() - }) -} - -fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) -> String { - let new_clang_key = match target { - "aarch64-linux-android" => Some("aarch64"), - "armv7-linux-androideabi" => Some("armv7a"), - "i686-linux-android" => Some("i686"), - "x86_64-linux-android" => Some("x86_64"), - _ => None, - }; - - let new_clang = new_clang_key - .map(|key| { - NEW_STANDALONE_ANDROID_COMPILERS - .iter() - .find(|x| x.starts_with(key)) - }) - .unwrap_or(None); - - if let Some(new_clang) = new_clang { - if Command::new(new_clang).output().is_ok() { - return (*new_clang).into(); - } - } - - let target = target - .replace("armv7neon", "arm") - .replace("armv7", "arm") - .replace("thumbv7neon", "arm") - .replace("thumbv7", "arm"); - let gnu_compiler = format!("{}-{}", target, gnu); - let clang_compiler = format!("{}-{}", target, clang); - - // On Windows, the Android clang compiler is provided as a `.cmd` file instead - // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the - // `.cmd` is explicitly appended to the command name, so we do that here. - let clang_compiler_cmd = format!("{}-{}.cmd", target, clang); - - // Check if gnu compiler is present - // if not, use clang - if Command::new(&gnu_compiler).output().is_ok() { - gnu_compiler - } else if host.contains("windows") && Command::new(&clang_compiler_cmd).output().is_ok() { - clang_compiler_cmd - } else { - clang_compiler - } -} diff --git a/third_party/cargo/vendor/cc-1.0.66/.cargo-checksum.json b/third_party/cargo/vendor/cc-1.0.66/.cargo-checksum.json new file mode 100644 index 0000000..45e9e7c --- /dev/null +++ b/third_party/cargo/vendor/cc-1.0.66/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"e7f53256b803536940678cee654d7e2318882aa7cd163acbe8be0caa72087b65","Cargo.toml":"ecb8c7e0fccad7f2d42412b5a227bf51f8e53b9fd526e036fc1b8f41c5024a68","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"3055cc70608f92dab0dcd10338264357ef891f01d02219fa64457b4aa016936b","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"e1a05e4a092b903dbbc45612ee924c038585d5f680233792afc551000eb6aac5","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cc-1.0.66/BUILD.bazel b/third_party/cargo/vendor/cc-1.0.66/BUILD.bazel new file mode 100644 index 0000000..f797aab --- /dev/null +++ b/third_party/cargo/vendor/cc-1.0.66/BUILD.bazel @@ -0,0 +1,86 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_binary( + # Prefix bin name to disambiguate from (probable) collision with lib name + # N.B.: The exact form of this is subject to change. + name = "cargo_bin_gcc_shim", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/bin/gcc-shim.rs", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.0.66", + # buildifier: leave-alone + deps = [ + # Binaries get an implicit dependency on their crate's lib + ":cc", + ], +) + +rust_library( + name = "cc", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.0.66", + # buildifier: leave-alone + deps = [ + ], +) + +# Unsupported target "cc_env" with type "test" omitted + +# Unsupported target "cflags" with type "test" omitted + +# Unsupported target "cxxflags" with type "test" omitted + +# Unsupported target "test" with type "test" omitted diff --git a/third_party/cargo/vendor/cc-1.0.66/Cargo.lock b/third_party/cargo/vendor/cc-1.0.66/Cargo.lock new file mode 100644 index 0000000..19dae76 --- /dev/null +++ b/third_party/cargo/vendor/cc-1.0.66/Cargo.lock @@ -0,0 +1,145 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "cc" +version = "1.0.66" +dependencies = [ + "jobserver", + "tempfile", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/cargo/vendor/cc-1.0.66/Cargo.toml b/third_party/cargo/vendor/cc-1.0.66/Cargo.toml new file mode 100644 index 0000000..4590bc2 --- /dev/null +++ b/third_party/cargo/vendor/cc-1.0.66/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "cc" +version = "1.0.66" +authors = ["Alex Crichton "] +exclude = ["/.github", "/.travis.yml", "/appveyor.yml"] +description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" +homepage = "https://github.com/alexcrichton/cc-rs" +documentation = "https://docs.rs/cc" +readme = "README.md" +keywords = ["build-dependencies"] +categories = ["development-tools::build-utils"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cc-rs" +[dependencies.jobserver] +version = "0.1.16" +optional = true +[dev-dependencies.tempfile] +version = "3" + +[features] +parallel = ["jobserver"] diff --git a/third_party/cargo/vendor/autocfg-1.0.0/LICENSE-APACHE b/third_party/cargo/vendor/cc-1.0.66/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/autocfg-1.0.0/LICENSE-APACHE rename to third_party/cargo/vendor/cc-1.0.66/LICENSE-APACHE diff --git a/third_party/cargo/vendor/cc-1.0.54/LICENSE-MIT b/third_party/cargo/vendor/cc-1.0.66/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/LICENSE-MIT rename to third_party/cargo/vendor/cc-1.0.66/LICENSE-MIT diff --git a/third_party/cargo/vendor/cc-1.0.66/README.md b/third_party/cargo/vendor/cc-1.0.66/README.md new file mode 100644 index 0000000..af80281 --- /dev/null +++ b/third_party/cargo/vendor/cc-1.0.66/README.md @@ -0,0 +1,222 @@ +# cc-rs + +A library to compile C/C++/assembly into a Rust library/application. + +[Documentation](https://docs.rs/cc) + +A simple library meant to be used as a build dependency with Cargo packages in +order to build a set of C/C++ files into a static archive. This crate calls out +to the most relevant compiler for a platform, for example using `cl` on MSVC. + +## Using cc-rs + +First, you'll want to both add a build script for your crate (`build.rs`) and +also add this crate to your `Cargo.toml` via: + +```toml +[build-dependencies] +cc = "1.0" +``` + +Next up, you'll want to write a build script like so: + +```rust,no_run +// build.rs + +fn main() { + cc::Build::new() + .file("foo.c") + .file("bar.c") + .compile("foo"); +} +``` + +And that's it! Running `cargo build` should take care of the rest and your Rust +application will now have the C files `foo.c` and `bar.c` compiled into a file +named `libfoo.a`. If the C files contain + +```c +void foo_function(void) { ... } +``` + +and + +```c +int32_t bar_function(int32_t x) { ... } +``` + +you can call them from Rust by declaring them in +your Rust code like so: + +```rust,no_run +extern { + fn foo_function(); + fn bar_function(x: i32) -> i32; +} + +pub fn call() { + unsafe { + foo_function(); + bar_function(42); + } +} + +fn main() { + // ... +} +``` + +See [the Rustonomicon](https://doc.rust-lang.org/nomicon/ffi.html) for more details. + +## External configuration via environment variables + +To control the programs and flags used for building, the builder can set a +number of different environment variables. + +* `CFLAGS` - a series of space separated flags passed to compilers. Note that + individual flags cannot currently contain spaces, so doing + something like: `-L=foo\ bar` is not possible. +* `CC` - the actual C compiler used. Note that this is used as an exact + executable name, so (for example) no extra flags can be passed inside + this variable, and the builder must ensure that there aren't any + trailing spaces. This compiler must understand the `-c` flag. For + certain `TARGET`s, it also is assumed to know about other flags (most + common is `-fPIC`). +* `AR` - the `ar` (archiver) executable to use to build the static library. +* `CRATE_CC_NO_DEFAULTS` - the default compiler flags may cause conflicts in some cross compiling scenarios. Setting this variable will disable the generation of default compiler flags. +* `CXX...` - see [C++ Support](#c-support). + +Each of these variables can also be supplied with certain prefixes and suffixes, +in the following prioritized order: + +1. `_` - for example, `CC_x86_64-unknown-linux-gnu` +2. `_` - for example, `CC_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` +4. `` - a plain `CC`, `AR` as above. + +If none of these variables exist, cc-rs uses built-in defaults + +In addition to the above optional environment variables, `cc-rs` has some +functions with hard requirements on some variables supplied by [cargo's +build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, +and `HOST` variables. + +[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script + +## Optional features + +### Parallel + +Currently cc-rs supports parallel compilation (think `make -jN`) but this +feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, +you can change your dependency to: + +```toml +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +``` + +By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it +will limit it to the number of cpus on the machine. If you are using cargo, +use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS` +is supplied by cargo. + +## Compile-time Requirements + +To work properly this crate needs access to a C compiler when the build script +is being run. This crate does not ship a C compiler with it. The compiler +required varies per platform, but there are three broad categories: + +* Unix platforms require `cc` to be the C compiler. This can be found by + installing cc/clang on Linux distributions and Xcode on OSX, for example. +* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) + require `cl.exe` to be available and in `PATH`. This is typically found in + standard Visual Studio installations and the `PATH` can be set up by running + the appropriate developer tools shell. +* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) + require `cc` to be available in `PATH`. We recommend the + [MinGW-w64](http://mingw-w64.org) distribution, which is using the + [Win-builds](http://win-builds.org) installation system. + You may also acquire it via + [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure + to install the appropriate architecture corresponding to your installation of + rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible + only with 32-bit rust compiler. + +[msys2-help]: http://github.com/rust-lang/rust#building-on-windows + +## C++ support + +`cc-rs` supports C++ libraries compilation by using the `cpp` method on +`Build`: + +```rust,no_run +fn main() { + cc::Build::new() + .cpp(true) // Switch to C++ library compilation. + .file("foo.cpp") + .compile("libfoo.a"); +} +``` + +For C++ libraries, the `CXX` and `CXXFLAGS` environment variables are used instead of `CC` and `CFLAGS`. + +The C++ standard library may be linked to the crate target. By default it's `libc++` for OS X, FreeBSD, and OpenBSD, `libc++_shared` for Android, nothing for MSVC, and `libstdc++` for anything else. It can be changed in one of two ways: + +1. by using the `cpp_link_stdlib` method on `Build`: + ```rust,no-run + fn main() { + cc::Build::new() + .cpp(true) + .file("foo.cpp") + .cpp_link_stdlib("stdc++") // use libstdc++ + .compile("libfoo.a"); + } + ``` +2. by setting the `CXXSTDLIB` environment variable. + +In particular, for Android you may want to [use `c++_static` if you have at most one shared library](https://developer.android.com/ndk/guides/cpp-support). + +Remember that C++ does name mangling so `extern "C"` might be required to enable Rust linker to find your functions. + +## CUDA C++ support + +`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method +on `Build` (currently for GNU/Clang toolchains only): + +```rust,no_run +fn main() { + cc::Build::new() + // Switch to CUDA C++ library compilation using NVCC. + .cuda(true) + // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X). + .flag("-gencode").flag("arch=compute_52,code=sm_52") + // Generate code for Maxwell (Jetson TX1). + .flag("-gencode").flag("arch=compute_53,code=sm_53") + // Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp). + .flag("-gencode").flag("arch=compute_61,code=sm_61") + // Generate code for Pascal (Tesla P100). + .flag("-gencode").flag("arch=compute_60,code=sm_60") + // Generate code for Pascal (Jetson TX2). + .flag("-gencode").flag("arch=compute_62,code=sm_62") + .file("bar.cu") + .compile("libbar.a"); +} +``` + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/cc-1.0.54/src/bin/gcc-shim.rs b/third_party/cargo/vendor/cc-1.0.66/src/bin/gcc-shim.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/src/bin/gcc-shim.rs rename to third_party/cargo/vendor/cc-1.0.66/src/bin/gcc-shim.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/src/com.rs b/third_party/cargo/vendor/cc-1.0.66/src/com.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/src/com.rs rename to third_party/cargo/vendor/cc-1.0.66/src/com.rs diff --git a/third_party/cargo/vendor/cc-1.0.66/src/lib.rs b/third_party/cargo/vendor/cc-1.0.66/src/lib.rs new file mode 100644 index 0000000..9814ea7 --- /dev/null +++ b/third_party/cargo/vendor/cc-1.0.66/src/lib.rs @@ -0,0 +1,3068 @@ +//! A library for build scripts to compile custom C code +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cc = "1.0" +//! ``` +//! +//! The purpose of this crate is to provide the utility functions necessary to +//! compile C code into a static archive which is then linked into a Rust crate. +//! Configuration is available through the `Build` struct. +//! +//! This crate will automatically detect situations such as cross compilation or +//! other environment variables set by Cargo and will build code appropriately. +//! +//! The crate is not limited to C code, it can accept any source code that can +//! be passed to a C or C++ compiler. As such, assembly files with extensions +//! `.s` (gcc/clang) and `.asm` (MSVC) can also be compiled. +//! +//! [`Build`]: struct.Build.html +//! +//! # Parallelism +//! +//! To parallelize computation, enable the `parallel` feature for the crate. +//! +//! ```toml +//! [build-dependencies] +//! cc = { version = "1.0", features = ["parallel"] } +//! ``` +//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS` +//! environment variable to the desired amount. +//! +//! Cargo will also set this environment variable when executed with the `-jN` flag. +//! +//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can +//! also specify the build parallelism. +//! +//! # Examples +//! +//! Use the `Build` struct to compile `src/foo.c`: +//! +//! ```no_run +//! fn main() { +//! cc::Build::new() +//! .file("src/foo.c") +//! .define("FOO", Some("bar")) +//! .include("src") +//! .compile("foo"); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/cc/1.0")] +#![cfg_attr(test, deny(warnings))] +#![allow(deprecated)] +#![deny(missing_docs)] + +use std::collections::HashMap; +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fmt::{self, Display}; +use std::fs; +use std::io::{self, BufRead, BufReader, Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; + +// These modules are all glue to support reading the MSVC version from +// the registry and from COM interfaces +#[cfg(windows)] +mod registry; +#[cfg(windows)] +#[macro_use] +mod winapi; +#[cfg(windows)] +mod com; +#[cfg(windows)] +mod setup_config; + +pub mod windows_registry; + +/// A builder for compilation of a native library. +/// +/// A `Build` is the main type of the `cc` crate and is used to control all the +/// various configuration options and such of a compile. You'll find more +/// documentation on each method itself. +#[derive(Clone, Debug)] +pub struct Build { + include_directories: Vec, + definitions: Vec<(String, Option)>, + objects: Vec, + flags: Vec, + flags_supported: Vec, + known_flag_support_status: Arc>>, + ar_flags: Vec, + no_default_flags: bool, + files: Vec, + cpp: bool, + cpp_link_stdlib: Option>, + cpp_set_stdlib: Option, + cuda: bool, + target: Option, + host: Option, + out_dir: Option, + opt_level: Option, + debug: Option, + force_frame_pointer: Option, + env: Vec<(OsString, OsString)>, + compiler: Option, + archiver: Option, + cargo_metadata: bool, + pic: Option, + use_plt: Option, + static_crt: Option, + shared_flag: Option, + static_flag: Option, + warnings_into_errors: bool, + warnings: Option, + extra_warnings: Option, + env_cache: Arc>>>, + apple_sdk_root_cache: Arc>>, +} + +/// Represents the types of errors that may occur while using cc-rs. +#[derive(Clone, Debug)] +enum ErrorKind { + /// Error occurred while performing I/O. + IOError, + /// Invalid architecture supplied. + ArchitectureInvalid, + /// Environment variable not found, with the var in question as extra info. + EnvVarNotFound, + /// Error occurred while using external tools (ie: invocation of compiler). + ToolExecError, + /// Error occurred due to missing external tools. + ToolNotFound, +} + +/// Represents an internal error that occurred, with an explanation. +#[derive(Clone, Debug)] +pub struct Error { + /// Describes the kind of error that occurred. + kind: ErrorKind, + /// More explanation of error that occurred. + message: String, +} + +impl Error { + fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind: kind, + message: message.to_owned(), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Error { + Error::new(ErrorKind::IOError, &format!("{}", e)) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}: {}", self.kind, self.message) + } +} + +impl std::error::Error for Error {} + +/// Configuration used to represent an invocation of a C compiler. +/// +/// This can be used to figure out what compiler is in use, what the arguments +/// to it are, and what the environment variables look like for the compiler. +/// This can be used to further configure other build systems (e.g. forward +/// along CC and/or CFLAGS) or the `to_command` method can be used to run the +/// compiler itself. +#[derive(Clone, Debug)] +pub struct Tool { + path: PathBuf, + cc_wrapper_path: Option, + cc_wrapper_args: Vec, + args: Vec, + env: Vec<(OsString, OsString)>, + family: ToolFamily, + cuda: bool, + removed_args: Vec, +} + +/// Represents the family of tools this tool belongs to. +/// +/// Each family of tools differs in how and what arguments they accept. +/// +/// Detection of a family is done on best-effort basis and may not accurately reflect the tool. +#[derive(Copy, Clone, Debug, PartialEq)] +enum ToolFamily { + /// Tool is GNU Compiler Collection-like. + Gnu, + /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags + /// and its cross-compilation approach is different. + Clang, + /// Tool is the MSVC cl.exe. + Msvc { clang_cl: bool }, +} + +impl ToolFamily { + /// What the flag to request debug info for this family of tools look like + fn add_debug_flags(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("-Z7".into()); + } + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-g".into()); + } + } + } + + /// What the flag to force frame pointers. + fn add_force_frame_pointer(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-fno-omit-frame-pointer".into()); + } + _ => (), + } + } + + /// What the flags to enable all warnings + fn warnings_flags(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "-W4", + ToolFamily::Gnu | ToolFamily::Clang => "-Wall", + } + } + + /// What the flags to enable extra warnings + fn extra_warnings_flags(&self) -> Option<&'static str> { + match *self { + ToolFamily::Msvc { .. } => None, + ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"), + } + } + + /// What the flag to turn warning into errors + fn warnings_to_errors_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "-WX", + ToolFamily::Gnu | ToolFamily::Clang => "-Werror", + } + } + + fn verbose_stderr(&self) -> bool { + *self == ToolFamily::Clang + } +} + +/// Represents an object. +/// +/// This is a source file -> object file pair. +#[derive(Clone, Debug)] +struct Object { + src: PathBuf, + dst: PathBuf, +} + +impl Object { + /// Create a new source file -> object file pair. + fn new(src: PathBuf, dst: PathBuf) -> Object { + Object { src: src, dst: dst } + } +} + +impl Build { + /// Construct a new instance of a blank set of configuration. + /// + /// This builder is finished with the [`compile`] function. + /// + /// [`compile`]: struct.Build.html#method.compile + pub fn new() -> Build { + Build { + include_directories: Vec::new(), + definitions: Vec::new(), + objects: Vec::new(), + flags: Vec::new(), + flags_supported: Vec::new(), + known_flag_support_status: Arc::new(Mutex::new(HashMap::new())), + ar_flags: Vec::new(), + no_default_flags: false, + files: Vec::new(), + shared_flag: None, + static_flag: None, + cpp: false, + cpp_link_stdlib: None, + cpp_set_stdlib: None, + cuda: false, + target: None, + host: None, + out_dir: None, + opt_level: None, + debug: None, + force_frame_pointer: None, + env: Vec::new(), + compiler: None, + archiver: None, + cargo_metadata: true, + pic: None, + use_plt: None, + static_crt: None, + warnings: None, + extra_warnings: None, + warnings_into_errors: false, + env_cache: Arc::new(Mutex::new(HashMap::new())), + apple_sdk_root_cache: Arc::new(Mutex::new(HashMap::new())), + } + } + + /// Add a directory to the `-I` or include path for headers + /// + /// # Example + /// + /// ```no_run + /// use std::path::Path; + /// + /// let library_path = Path::new("/path/to/library"); + /// + /// cc::Build::new() + /// .file("src/foo.c") + /// .include(library_path) + /// .include("src") + /// .compile("foo"); + /// ``` + pub fn include>(&mut self, dir: P) -> &mut Build { + self.include_directories.push(dir.as_ref().to_path_buf()); + self + } + + /// Add multiple directories to the `-I` include path. + /// + /// # Example + /// + /// ```no_run + /// # use std::path::Path; + /// # let condition = true; + /// # + /// let mut extra_dir = None; + /// if condition { + /// extra_dir = Some(Path::new("/path/to")); + /// } + /// + /// cc::Build::new() + /// .file("src/foo.c") + /// .includes(extra_dir) + /// .compile("foo"); + /// ``` + pub fn includes

(&mut self, dirs: P) -> &mut Build + where + P: IntoIterator, + P::Item: AsRef, + { + for dir in dirs { + self.include(dir); + } + self + } + + /// Specify a `-D` variable with an optional value. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .define("FOO", "BAR") + /// .define("BAZ", None) + /// .compile("foo"); + /// ``` + pub fn define<'a, V: Into>>(&mut self, var: &str, val: V) -> &mut Build { + self.definitions + .push((var.to_string(), val.into().map(|s| s.to_string()))); + self + } + + /// Add an arbitrary object file to link in + pub fn object>(&mut self, obj: P) -> &mut Build { + self.objects.push(obj.as_ref().to_path_buf()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag("-ffunction-sections") + /// .compile("foo"); + /// ``` + pub fn flag(&mut self, flag: &str) -> &mut Build { + self.flags.push(flag.to_string()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .file("src/bar.c") + /// .ar_flag("/NODEFAULTLIB:libc.dll") + /// .compile("foo"); + /// ``` + + pub fn ar_flag(&mut self, flag: &str) -> &mut Build { + self.ar_flags.push(flag.to_string()); + self + } + + fn ensure_check_file(&self) -> Result { + let out_dir = self.get_out_dir()?; + let src = if self.cuda { + assert!(self.cpp); + out_dir.join("flag_check.cu") + } else if self.cpp { + out_dir.join("flag_check.cpp") + } else { + out_dir.join("flag_check.c") + }; + + if !src.exists() { + let mut f = fs::File::create(&src)?; + write!(f, "int main(void) {{ return 0; }}")?; + } + + Ok(src) + } + + /// Run the compiler to test if it accepts the given flag. + /// + /// For a convenience method for setting flags conditionally, + /// see `flag_if_supported()`. + /// + /// It may return error if it's unable to run the compiler with a test file + /// (e.g. the compiler is missing or a write to the `out_dir` failed). + /// + /// Note: Once computed, the result of this call is stored in the + /// `known_flag_support` field. If `is_flag_supported(flag)` + /// is called again, the result will be read from the hash table. + pub fn is_flag_supported(&self, flag: &str) -> Result { + let mut known_status = self.known_flag_support_status.lock().unwrap(); + if let Some(is_supported) = known_status.get(flag).cloned() { + return Ok(is_supported); + } + + let out_dir = self.get_out_dir()?; + let src = self.ensure_check_file()?; + let obj = out_dir.join("flag_check"); + let target = self.get_target()?; + let host = self.get_host()?; + let mut cfg = Build::new(); + cfg.flag(flag) + .target(&target) + .opt_level(0) + .host(&host) + .debug(false) + .cpp(self.cpp) + .cuda(self.cuda); + let mut compiler = cfg.try_get_compiler()?; + + // Clang uses stderr for verbose output, which yields a false positive + // result if the CFLAGS/CXXFLAGS include -v to aid in debugging. + if compiler.family.verbose_stderr() { + compiler.remove_arg("-v".into()); + } + + let mut cmd = compiler.to_command(); + let is_arm = target.contains("aarch64") || target.contains("arm"); + let clang = compiler.family == ToolFamily::Clang; + command_add_output_file( + &mut cmd, + &obj, + self.cuda, + target.contains("msvc"), + clang, + false, + is_arm, + ); + + // We need to explicitly tell msvc not to link and create an exe + // in the root directory of the crate + if target.contains("msvc") && !self.cuda { + cmd.arg("-c"); + } + + cmd.arg(&src); + + let output = cmd.output()?; + let is_supported = output.stderr.is_empty(); + + known_status.insert(flag.to_owned(), is_supported); + Ok(is_supported) + } + + /// Add an arbitrary flag to the invocation of the compiler if it supports it + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag_if_supported("-Wlogical-op") // only supported by GCC + /// .flag_if_supported("-Wunreachable-code") // only supported by clang + /// .compile("foo"); + /// ``` + pub fn flag_if_supported(&mut self, flag: &str) -> &mut Build { + self.flags_supported.push(flag.to_string()); + self + } + + /// Set the `-shared` flag. + /// + /// When enabled, the compiler will produce a shared object which can + /// then be linked with other objects to form an executable. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .compile("libfoo.so"); + /// ``` + pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build { + self.shared_flag = Some(shared_flag); + self + } + + /// Set the `-static` flag. + /// + /// When enabled on systems that support dynamic linking, this prevents + /// linking with the shared libraries. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .static_flag(true) + /// .compile("foo"); + /// ``` + pub fn static_flag(&mut self, static_flag: bool) -> &mut Build { + self.static_flag = Some(static_flag); + self + } + + /// Disables the generation of default compiler flags. The default compiler + /// flags may cause conflicts in some cross compiling scenarios. + /// + /// Setting the `CRATE_CC_NO_DEFAULTS` environment variable has the same + /// effect as setting this to `true`. The presence of the environment + /// variable and the value of `no_default_flags` will be OR'd together. + pub fn no_default_flags(&mut self, no_default_flags: bool) -> &mut Build { + self.no_default_flags = no_default_flags; + self + } + + /// Add a file which will be compiled + pub fn file>(&mut self, p: P) -> &mut Build { + self.files.push(p.as_ref().to_path_buf()); + self + } + + /// Add files which will be compiled + pub fn files

for Decomposed -where - P::Scalar: BaseFloat, - // FIXME: Investigate why this is needed! - P::Diff: VectorSpace, -{ - #[inline] - fn one() -> Decomposed { - Decomposed { - scale: P::Scalar::one(), - rot: R::one(), - disp: P::Diff::zero(), - } - } - - #[inline] - fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed { - let rot = R::look_at(center - eye, up); - let disp = rot.rotate_vector(P::origin() - eye); - Decomposed { - scale: P::Scalar::one(), - rot: rot, - disp: disp, - } - } - - #[inline] - fn transform_vector(&self, vec: P::Diff) -> P::Diff { - self.rot.rotate_vector(vec * self.scale) - } - - #[inline] - fn inverse_transform_vector(&self, vec: P::Diff) -> Option { - if ulps_eq!(self.scale, &P::Scalar::zero()) { - None - } else { - Some(self.rot.invert().rotate_vector(vec / self.scale)) - } - } - - #[inline] - fn transform_point(&self, point: P) -> P { - self.rot.rotate_point(point * self.scale) + self.disp - } - - fn concat(&self, other: &Decomposed) -> Decomposed { - Decomposed { - scale: self.scale * other.scale, - rot: self.rot * other.rot, - disp: self.rot.rotate_vector(other.disp * self.scale) + self.disp, - } - } - - fn inverse_transform(&self) -> Option> { - if ulps_eq!(self.scale, &P::Scalar::zero()) { - None - } else { - let s = P::Scalar::one() / self.scale; - let r = self.rot.invert(); - let d = r.rotate_vector(self.disp.clone()) * -s; - Some(Decomposed { - scale: s, - rot: r, - disp: d, - }) - } - } -} - -pub trait Transform2: Transform> + Into> {} -pub trait Transform3: Transform> + Into> {} - -impl> From, R>> for Matrix3 { - fn from(dec: Decomposed, R>) -> Matrix3 { - let m: Matrix2<_> = dec.rot.into(); - let mut m: Matrix3<_> = (&m * dec.scale).into(); - m.z = dec.disp.extend(S::one()); - m - } -} - -impl> From, R>> for Matrix4 { - fn from(dec: Decomposed, R>) -> Matrix4 { - let m: Matrix3<_> = dec.rot.into(); - let mut m: Matrix4<_> = (&m * dec.scale).into(); - m.w = dec.disp.extend(S::one()); - m - } -} - -impl> Transform2 for Decomposed, R> {} - -impl> Transform3 for Decomposed, R> {} - -impl approx::AbsDiffEq for Decomposed -where - S: approx::AbsDiffEq, - S::Scalar: approx::AbsDiffEq, - R: approx::AbsDiffEq, -{ - type Epsilon = E; - - #[inline] - fn default_epsilon() -> E { - E::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: E) -> bool { - S::Scalar::abs_diff_eq(&self.scale, &other.scale, epsilon) - && R::abs_diff_eq(&self.rot, &other.rot, epsilon) - && S::abs_diff_eq(&self.disp, &other.disp, epsilon) - } -} - -impl approx::RelativeEq for Decomposed -where - S: approx::RelativeEq, - S::Scalar: approx::RelativeEq, - R: approx::RelativeEq, -{ - #[inline] - fn default_max_relative() -> E { - E::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: E, max_relative: E) -> bool { - S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative) - && R::relative_eq(&self.rot, &other.rot, epsilon, max_relative) - && S::relative_eq(&self.disp, &other.disp, epsilon, max_relative) - } -} - -impl approx::UlpsEq for Decomposed -where - S: approx::UlpsEq, - S::Scalar: approx::UlpsEq, - R: approx::UlpsEq, -{ - #[inline] - fn default_max_ulps() -> u32 { - E::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: E, max_ulps: u32) -> bool { - S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps) - && R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps) - && S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps) - } -} - -#[cfg(feature = "serde")] -#[doc(hidden)] -mod serde_ser { - use structure::VectorSpace; - use super::Decomposed; - use serde::{self, Serialize}; - use serde::ser::SerializeStruct; - - impl Serialize for Decomposed - where - V: Serialize + VectorSpace, - V::Scalar: Serialize, - R: Serialize, - { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut struc = serializer.serialize_struct("Decomposed", 3)?; - struc.serialize_field("scale", &self.scale)?; - struc.serialize_field("rot", &self.rot)?; - struc.serialize_field("disp", &self.disp)?; - struc.end() - } - } -} - -#[cfg(feature = "serde")] -#[doc(hidden)] -mod serde_de { - use structure::VectorSpace; - use super::Decomposed; - use serde::{self, Deserialize}; - use std::marker::PhantomData; - use std::fmt; - - enum DecomposedField { - Scale, - Rot, - Disp, - } - - impl<'a> Deserialize<'a> for DecomposedField { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'a>, - { - struct DecomposedFieldVisitor; - - impl<'b> serde::de::Visitor<'b> for DecomposedFieldVisitor { - type Value = DecomposedField; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("`scale`, `rot` or `disp`") - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - match value { - "scale" => Ok(DecomposedField::Scale), - "rot" => Ok(DecomposedField::Rot), - "disp" => Ok(DecomposedField::Disp), - _ => Err(serde::de::Error::custom("expected scale, rot or disp")), - } - } - } - - deserializer.deserialize_str(DecomposedFieldVisitor) - } - } - - impl<'a, S: VectorSpace, R> Deserialize<'a> for Decomposed - where - S: Deserialize<'a>, - S::Scalar: Deserialize<'a>, - R: Deserialize<'a>, - { - fn deserialize(deserializer: D) -> Result, D::Error> - where - D: serde::de::Deserializer<'a>, - { - const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"]; - deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData)) - } - } - - struct DecomposedVisitor(PhantomData<(S, R)>); - - impl<'a, S: VectorSpace, R> serde::de::Visitor<'a> for DecomposedVisitor - where - S: Deserialize<'a>, - S::Scalar: Deserialize<'a>, - R: Deserialize<'a>, - { - type Value = Decomposed; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("`scale`, `rot` and `disp` fields") - } - - fn visit_map(self, mut visitor: V) -> Result, V::Error> - where - V: serde::de::MapAccess<'a>, - { - let mut scale = None; - let mut rot = None; - let mut disp = None; - - while let Some(key) = visitor.next_key()? { - match key { - DecomposedField::Scale => { - scale = Some(visitor.next_value()?); - } - DecomposedField::Rot => { - rot = Some(visitor.next_value()?); - } - DecomposedField::Disp => { - disp = Some(visitor.next_value()?); - } - } - } - - let scale = match scale { - Some(scale) => scale, - None => return Err(serde::de::Error::missing_field("scale")), - }; - - let rot = match rot { - Some(rot) => rot, - None => return Err(serde::de::Error::missing_field("rot")), - }; - - let disp = match disp { - Some(disp) => disp, - None => return Err(serde::de::Error::missing_field("disp")), - }; - - Ok(Decomposed { - scale: scale, - rot: rot, - disp: disp, - }) - } - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/vector.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/vector.rs deleted file mode 100755 index 16b31d1..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/vector.rs +++ /dev/null @@ -1,1605 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use rand::distributions::{Distribution, Standard}; -use rand::Rng; -use num_traits::{Bounded, NumCast}; -use std::fmt; -use std::iter; -use std::mem; -use std::ops::*; - -use structure::*; - -use angle::Rad; -use approx; -use num::{BaseFloat, BaseNum}; - -#[cfg(feature = "simd")] -use simd::f32x4 as Simdf32x4; -#[cfg(feature = "simd")] -use simd::i32x4 as Simdi32x4; -#[cfg(feature = "simd")] -use simd::u32x4 as Simdu32x4; - -#[cfg(feature = "mint")] -use mint; - -/// A 1-dimensional vector. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Vector1 { - /// The x component of the vector. - pub x: S, -} - -/// A 2-dimensional vector. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Vector2 { - /// The x component of the vector. - pub x: S, - /// The y component of the vector. - pub y: S, -} - -/// A 3-dimensional vector. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Vector3 { - /// The x component of the vector. - pub x: S, - /// The y component of the vector. - pub y: S, - /// The z component of the vector. - pub z: S, -} - -/// A 4-dimensional vector. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Vector4 { - /// The x component of the vector. - pub x: S, - /// The y component of the vector. - pub y: S, - /// The z component of the vector. - pub z: S, - /// The w component of the vector. - pub w: S, -} - -// Utility macro for generating associated functions for the vectors -macro_rules! impl_vector { - ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { - impl $VectorN { - /// Construct a new vector, using the provided values. - #[inline] - pub const fn new($($field: S),+) -> $VectorN { - $VectorN { $($field: $field),+ } - } - - /// Perform the given operation on each field in the vector, returning a new point - /// constructed from the operations. - #[inline] - pub fn map(self, mut f: F) -> $VectorN - where F: FnMut(S) -> U - { - $VectorN { $($field: f(self.$field)),+ } - } - } - - /// The short constructor. - #[inline] - pub const fn $constructor($($field: S),+) -> $VectorN { - $VectorN::new($($field),+) - } - - impl $VectorN { - /// Component-wise casting to another type. - #[inline] - pub fn cast(&self) -> Option<$VectorN> { - $( - let $field = match NumCast::from(self.$field) { - Some(field) => field, - None => return None - }; - )+ - Some($VectorN { $($field),+ }) - } - } - - impl MetricSpace for $VectorN { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } - } - - impl Array for $VectorN { - type Element = S; - - #[inline] - fn len() -> usize { - $n - } - - #[inline] - fn from_value(scalar: S) -> $VectorN { - $VectorN { $($field: scalar),+ } - } - - #[inline] - fn sum(self) -> S where S: Add { - fold_array!(add, { $(self.$field),+ }) - } - - #[inline] - fn product(self) -> S where S: Mul { - fold_array!(mul, { $(self.$field),+ }) - } - - fn is_finite(&self) -> bool where S: BaseFloat { - $(self.$field.is_finite())&&+ - } - } - - impl Zero for $VectorN { - #[inline] - fn zero() -> $VectorN { - $VectorN::from_value(S::zero()) - } - - #[inline] - fn is_zero(&self) -> bool { - *self == $VectorN::zero() - } - } - - impl iter::Sum<$VectorN> for $VectorN { - #[inline] - fn sum>>(iter: I) -> $VectorN { - iter.fold($VectorN::zero(), Add::add) - } - } - - impl<'a, S: 'a + BaseNum> iter::Sum<&'a $VectorN> for $VectorN { - #[inline] - fn sum>>(iter: I) -> $VectorN { - iter.fold($VectorN::zero(), Add::add) - } - } - - impl VectorSpace for $VectorN { - type Scalar = S; - } - - impl> Neg for $VectorN { - type Output = $VectorN; - - #[inline] - fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } - } - - impl approx::AbsDiffEq for $VectorN { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ - } - } - - impl approx::RelativeEq for $VectorN { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ - } - } - - impl approx::UlpsEq for $VectorN { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ - } - } - - impl Distribution<$VectorN> for Standard - where Standard: Distribution, - S: BaseFloat { - #[inline] - fn sample(&self, rng: &mut R) -> $VectorN { - $VectorN { $($field: rng.gen()),+ } - } - } - - impl Bounded for $VectorN { - #[inline] - fn min_value() -> $VectorN { - $VectorN { $($field: S::min_value()),+ } - } - - #[inline] - fn max_value() -> $VectorN { - $VectorN { $($field: S::max_value()),+ } - } - } - - impl_operator!( Add<$VectorN > for $VectorN { - fn add(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field + rhs.$field),+) } - }); - impl_assignment_operator!( AddAssign<$VectorN > for $VectorN { - fn add_assign(&mut self, other) { $(self.$field += other.$field);+ } - }); - - impl_operator!( Sub<$VectorN > for $VectorN { - fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } - }); - impl_assignment_operator!( SubAssign<$VectorN > for $VectorN { - fn sub_assign(&mut self, other) { $(self.$field -= other.$field);+ } - }); - - impl_operator!( Mul for $VectorN { - fn mul(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field * scalar),+) } - }); - impl_assignment_operator!( MulAssign for $VectorN { - fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } - }); - - impl_operator!( Div for $VectorN { - fn div(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field / scalar),+) } - }); - impl_assignment_operator!( DivAssign for $VectorN { - fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } - }); - - impl_operator!( Rem for $VectorN { - fn rem(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field % scalar),+) } - }); - impl_assignment_operator!( RemAssign for $VectorN { - fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } - }); - - impl ElementWise for $VectorN { - #[inline] fn add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } - #[inline] fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } - #[inline] fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } - #[inline] fn div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } - #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } - - #[inline] fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } - } - - impl ElementWise for $VectorN { - #[inline] fn add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } - #[inline] fn sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } - #[inline] fn mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } - #[inline] fn div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } - #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } - - #[inline] fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } - } - - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - - impl_index_operators!($VectorN, $n, S, usize); - impl_index_operators!($VectorN, $n, [S], Range); - impl_index_operators!($VectorN, $n, [S], RangeTo); - impl_index_operators!($VectorN, $n, [S], RangeFrom); - impl_index_operators!($VectorN, $n, [S], RangeFull); - } -} - -// Utility macro for generating associated functions for the vectors -// mainly duplication -#[cfg(feature = "simd")] -macro_rules! impl_vector_default { - ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { - impl $VectorN { - /// Construct a new vector, using the provided values. - #[inline] - pub const fn new($($field: S),+) -> $VectorN { - $VectorN { $($field: $field),+ } - } - } - - /// The short constructor. - #[inline] - pub fn $constructor($($field: S),+) -> $VectorN { - $VectorN::new($($field),+) - } - - impl $VectorN { - /// True if all entries in the vector are finite - pub fn is_finite(&self) -> bool { - $(self.$field.is_finite())&&+ - } - } - - impl $VectorN { - /// Component-wise casting to another type. - #[inline] - pub fn cast(&self) -> Option<$VectorN> { - $( - let $field = match NumCast::from(self.$field) { - Some(field) => field, - None => return None - }; - )+ - Some($VectorN { $($field),+ }) - } - } - - impl MetricSpace for $VectorN { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } - } - - impl Array for $VectorN { - type Element = S; - - #[inline] - fn len() -> usize { - $n - } - - #[inline] - fn from_value(scalar: S) -> $VectorN { - $VectorN { $($field: scalar),+ } - } - - #[inline] - fn sum(self) -> S where S: Add { - fold_array!(add, { $(self.$field),+ }) - } - - #[inline] - fn product(self) -> S where S: Mul { - fold_array!(mul, { $(self.$field),+ }) - } - - fn is_finite(&self) -> bool where S: BaseFloat { - $(self.$field.is_finite())&&+ - } - } - - impl Zero for $VectorN { - #[inline] - fn zero() -> $VectorN { - $VectorN::from_value(S::zero()) - } - - #[inline] - fn is_zero(&self) -> bool { - *self == $VectorN::zero() - } - } - - impl iter::Sum for $VectorN { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) - } - } - - impl<'a, S: 'a + BaseNum> iter::Sum<&'a Self> for $VectorN { - #[inline] - fn sum>(iter: I) -> Self { - iter.fold(Self::zero(), Add::add) - } - } - - impl VectorSpace for $VectorN { - type Scalar = S; - } - - impl> Neg for $VectorN { - type Output = $VectorN; - - #[inline] - default fn neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } - } - - impl approx::AbsDiffEq for $VectorN { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ - } - } - - impl approx::RelativeEq for $VectorN { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ - } - } - - impl approx::UlpsEq for $VectorN { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ - } - } - - impl Distribution<$VectorN> for Standard - where S: BaseFloat, - Standard: Distribution { - #[inline] - fn sample(&self, rng: &mut R) -> $VectorN { - $VectorN { $($field: rng.gen()),+ } - } - } - - impl_operator_default!( Add<$VectorN > for $VectorN { - fn add(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field + rhs.$field),+) } - }); - - impl_assignment_operator_default!( AddAssign<$VectorN > for $VectorN { - fn add_assign(&mut self, other) { $(self.$field += other.$field);+ } - }); - - impl_operator_default!( Sub<$VectorN > for $VectorN { - fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } - }); - - impl_assignment_operator_default!( SubAssign<$VectorN > for $VectorN { - fn sub_assign(&mut self, other) { $(self.$field -= other.$field);+ } - }); - - impl_operator_default!( Mul for $VectorN { - fn mul(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field * scalar),+) } - }); - - impl_assignment_operator_default!( MulAssign for $VectorN { - fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } - }); - - impl_operator_default!( Div for $VectorN { - fn div(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field / scalar),+) } - }); - - impl_assignment_operator_default!( DivAssign for $VectorN { - fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } - }); - - impl_operator!( Rem for $VectorN { - fn rem(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field % scalar),+) } - }); - impl_assignment_operator!( RemAssign for $VectorN { - fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } - }); - - impl ElementWise for $VectorN { - #[inline] default fn add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } - #[inline] default fn sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } - #[inline] default fn mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } - #[inline] default fn div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } - #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } - - #[inline] default fn add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } - #[inline] default fn sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } - #[inline] default fn mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } - #[inline] default fn div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } - } - - impl ElementWise for $VectorN { - #[inline] default fn add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } - #[inline] default fn sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } - #[inline] default fn mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } - #[inline] default fn div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } - #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } - - #[inline] default fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] default fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] default fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] default fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } - } - - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - impl_scalar_ops_default!($VectorN { $($field),+ }); - impl_scalar_ops!($VectorN { $($field),+ }); - - impl_index_operators!($VectorN, $n, S, usize); - impl_index_operators!($VectorN, $n, [S], Range); - impl_index_operators!($VectorN, $n, [S], RangeTo); - impl_index_operators!($VectorN, $n, [S], RangeFrom); - impl_index_operators!($VectorN, $n, [S], RangeFull); - } -} - -macro_rules! impl_scalar_ops { - ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { - impl_operator!(Mul<$VectorN<$S>> for $S { - fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) } - }); - impl_operator!(Div<$VectorN<$S>> for $S { - fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) } - }); - impl_operator!(Rem<$VectorN<$S>> for $S { - fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) } - }); - }; -} - -#[cfg(feature = "simd")] -macro_rules! impl_scalar_ops_default { - ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { - impl_operator_default!(Mul<$VectorN<$S>> for $S { - fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) } - }); - impl_operator_default!(Div<$VectorN<$S>> for $S { - fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) } - }); - impl_operator_default!(Rem<$VectorN<$S>> for $S { - fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) } - }); - }; -} - -impl_vector!(Vector1 { x }, 1, vec1); -impl_vector!(Vector2 { x, y }, 2, vec2); -impl_vector!(Vector3 { x, y, z }, 3, vec3); -#[cfg(not(feature = "simd"))] -impl_vector!(Vector4 { x, y, z, w }, 4, vec4); -#[cfg(feature = "simd")] -impl_vector_default!(Vector4 { x, y, z, w }, 4, vec4); - -impl_fixed_array_conversions!(Vector1 { x: 0 }, 1); -impl_fixed_array_conversions!(Vector2 { x: 0, y: 1 }, 2); -impl_fixed_array_conversions!(Vector3 { x: 0, y: 1, z: 2 }, 3); -impl_fixed_array_conversions!(Vector4 { x: 0, y: 1, z: 2, w: 3 }, 4); - -impl_tuple_conversions!(Vector1 { x }, (S,)); -impl_tuple_conversions!(Vector2 { x, y }, (S, S)); -impl_tuple_conversions!(Vector3 { x, y, z }, (S, S, S)); -impl_tuple_conversions!(Vector4 { x, y, z, w }, (S, S, S, S)); - -impl Vector1 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector1 { - Vector1::new(S::one()) - } - - impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, x); -} - -impl Vector2 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector2 { - Vector2::new(S::one(), S::zero()) - } - - /// A unit vector in the `y` direction. - #[inline] - pub fn unit_y() -> Vector2 { - Vector2::new(S::zero(), S::one()) - } - - /// The perpendicular dot product of the vector and `other`. - #[inline] - pub fn perp_dot(self, other: Vector2) -> S { - (self.x * other.y) - (self.y * other.x) - } - - /// Create a `Vector3`, using the `x` and `y` values from this vector, and the - /// provided `z`. - #[inline] - pub fn extend(self, z: S) -> Vector3 { - Vector3::new(self.x, self.y, z) - } - - impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xy); -} - -impl Vector3 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector3 { - Vector3::new(S::one(), S::zero(), S::zero()) - } - - /// A unit vector in the `y` direction. - #[inline] - pub fn unit_y() -> Vector3 { - Vector3::new(S::zero(), S::one(), S::zero()) - } - - /// A unit vector in the `z` direction. - #[inline] - pub fn unit_z() -> Vector3 { - Vector3::new(S::zero(), S::zero(), S::one()) - } - - /// Returns the cross product of the vector and `other`. - #[inline] - pub fn cross(self, other: Vector3) -> Vector3 { - Vector3::new( - (self.y * other.z) - (self.z * other.y), - (self.z * other.x) - (self.x * other.z), - (self.x * other.y) - (self.y * other.x), - ) - } - - /// Create a `Vector4`, using the `x`, `y` and `z` values from this vector, and the - /// provided `w`. - #[inline] - pub fn extend(self, w: S) -> Vector4 { - Vector4::new(self.x, self.y, self.z, w) - } - - /// Create a `Vector2`, dropping the `z` value. - #[inline] - pub fn truncate(self) -> Vector2 { - Vector2::new(self.x, self.y) - } - - impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xyz); -} - -impl Vector4 { - /// A unit vector in the `x` direction. - #[inline] - pub fn unit_x() -> Vector4 { - Vector4::new(S::one(), S::zero(), S::zero(), S::zero()) - } - - /// A unit vector in the `y` direction. - #[inline] - pub fn unit_y() -> Vector4 { - Vector4::new(S::zero(), S::one(), S::zero(), S::zero()) - } - - /// A unit vector in the `z` direction. - #[inline] - pub fn unit_z() -> Vector4 { - Vector4::new(S::zero(), S::zero(), S::one(), S::zero()) - } - - /// A unit vector in the `w` direction. - #[inline] - pub fn unit_w() -> Vector4 { - Vector4::new(S::zero(), S::zero(), S::zero(), S::one()) - } - - /// Create a `Vector3`, dropping the `w` value. - #[inline] - pub fn truncate(self) -> Vector3 { - Vector3::new(self.x, self.y, self.z) - } - - /// Create a `Vector3`, dropping the nth element. - #[inline] - pub fn truncate_n(&self, n: isize) -> Vector3 { - match n { - 0 => Vector3::new(self.y, self.z, self.w), - 1 => Vector3::new(self.x, self.z, self.w), - 2 => Vector3::new(self.x, self.y, self.w), - 3 => Vector3::new(self.x, self.y, self.z), - _ => panic!("{:?} is out of range", n), - } - } - - impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xyzw); -} - -/// Dot product of two vectors. -#[inline] -pub fn dot(a: V, b: V) -> V::Scalar -where - V::Scalar: BaseFloat, -{ - V::dot(a, b) -} - -impl InnerSpace for Vector1 { - #[inline] - fn dot(self, other: Vector1) -> S { - Vector1::mul_element_wise(self, other).sum() - } -} - -impl InnerSpace for Vector2 { - #[inline] - fn dot(self, other: Vector2) -> S { - Vector2::mul_element_wise(self, other).sum() - } - - #[inline] - fn angle(self, other: Vector2) -> Rad { - Rad::atan2(Self::perp_dot(self, other), Self::dot(self, other)) - } -} - -impl InnerSpace for Vector3 { - #[inline] - fn dot(self, other: Vector3) -> S { - Vector3::mul_element_wise(self, other).sum() - } - - #[inline] - fn angle(self, other: Vector3) -> Rad { - Rad::atan2(self.cross(other).magnitude(), Self::dot(self, other)) - } -} - -impl InnerSpace for Vector4 { - #[inline] - fn dot(self, other: Vector4) -> S { - Vector4::mul_element_wise(self, other).sum() - } -} - -impl fmt::Debug for Vector1 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector1 ")); - <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Vector2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector2 ")); - <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Vector3 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector3 ")); - <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Vector4 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Vector4 ")); - <[S; 4] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -#[cfg(feature = "simd")] -impl From for Vector4 { - #[inline] - fn from(f: Simdf32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [f32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Vector4 { - /// Compute and return the square root of each element. - #[inline] - pub fn sqrt_element_wide(self) -> Self { - let s: Simdf32x4 = self.into(); - s.sqrt().into() - } - - /// Compute and return the reciprocal of the square root of each element. - #[inline] - pub fn rsqrt_element_wide(self) -> Self { - let s: Simdf32x4 = self.into(); - s.approx_rsqrt().into() - } - - /// Compute and return the reciprocal of each element. - #[inline] - pub fn recip_element_wide(self) -> Self { - let s: Simdf32x4 = self.into(); - s.approx_reciprocal().into() - } -} - -#[cfg(feature = "simd")] -impl Into for Vector4 { - #[inline] - fn into(self) -> Simdf32x4 { - let self_ref: &[f32; 4] = self.as_ref(); - Simdf32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Add> for Vector4 { - fn add(lhs, rhs) -> Vector4 { - (lhs + rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Sub> for Vector4 { - fn sub(lhs, rhs) -> Vector4 { - (lhs - rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Mul for Vector4 { - fn mul(lhs, rhs) -> Vector4 { - (lhs * rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Div for Vector4 { - fn div(lhs, rhs) -> Vector4 { - (lhs / rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Neg for Vector4 { - fn neg(lhs) -> Vector4 { - (-lhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl AddAssign for Vector4 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl SubAssign for Vector4 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl MulAssign for Vector4 { - fn mul_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(feature = "simd")] -impl DivAssign for Vector4 { - fn div_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s / other).into(); - } -} - -#[cfg(feature = "simd")] -impl ElementWise for Vector4 { - #[inline] - fn add_element_wise(self, rhs: Vector4) -> Vector4 { - self + rhs - } - #[inline] - fn sub_element_wise(self, rhs: Vector4) -> Vector4 { - self - rhs - } - #[inline] - fn mul_element_wise(self, rhs: Vector4) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs: Simdf32x4 = rhs.into(); - (s * rhs).into() - } - #[inline] - fn div_element_wise(self, rhs: Vector4) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs: Simdf32x4 = rhs.into(); - (s / rhs).into() - } - - #[inline] - fn add_assign_element_wise(&mut self, rhs: Vector4) { - (*self) += rhs; - } - - #[inline] - fn sub_assign_element_wise(&mut self, rhs: Vector4) { - (*self) -= rhs; - } - - #[inline] - fn mul_assign_element_wise(&mut self, rhs: Vector4) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s * rhs).into(); - } - - #[inline] - fn div_assign_element_wise(&mut self, rhs: Vector4) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s * rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl ElementWise for Vector4 { - #[inline] - fn add_element_wise(self, rhs: f32) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs = Simdf32x4::splat(rhs); - (s + rhs).into() - } - - #[inline] - fn sub_element_wise(self, rhs: f32) -> Vector4 { - let s: Simdf32x4 = self.into(); - let rhs = Simdf32x4::splat(rhs); - (s - rhs).into() - } - - #[inline] - fn mul_element_wise(self, rhs: f32) -> Vector4 { - self * rhs - } - - #[inline] - fn div_element_wise(self, rhs: f32) -> Vector4 { - self / rhs - } - - #[inline] - fn add_assign_element_wise(&mut self, rhs: f32) { - let s: Simdf32x4 = (*self).into(); - let rhs = Simdf32x4::splat(rhs); - *self = (s + rhs).into(); - } - - #[inline] - fn sub_assign_element_wise(&mut self, rhs: f32) { - let s: Simdf32x4 = (*self).into(); - let rhs = Simdf32x4::splat(rhs); - *self = (s - rhs).into(); - } - - #[inline] - fn mul_assign_element_wise(&mut self, rhs: f32) { - (*self) *= rhs; - } - - #[inline] - fn div_assign_element_wise(&mut self, rhs: f32) { - (*self) /= rhs; - } -} - -#[cfg(feature = "simd")] -impl From for Vector4 { - #[inline] - fn from(f: Simdi32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [i32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Into for Vector4 { - #[inline] - fn into(self) -> Simdi32x4 { - let self_ref: &[i32; 4] = self.as_ref(); - Simdi32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdi32x4]; Add> for Vector4 { - fn add(lhs, rhs) -> Vector4 { - (lhs + rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdi32x4]; Sub> for Vector4 { - fn sub(lhs, rhs) -> Vector4 { - (lhs - rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdi32x4]; Mul for Vector4 { - fn mul(lhs, rhs) -> Vector4 { - (lhs * rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdi32x4]; Neg for Vector4 { - fn neg(lhs) -> Vector4 { - (-lhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl AddAssign for Vector4 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdi32x4 = (*self).into(); - let rhs: Simdi32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl SubAssign for Vector4 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdi32x4 = (*self).into(); - let rhs: Simdi32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl MulAssign for Vector4 { - fn mul_assign(&mut self, other: i32) { - let s: Simdi32x4 = (*self).into(); - let other = Simdi32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(feature = "simd")] -impl From for Vector4 { - #[inline] - fn from(f: Simdu32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [u32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Into for Vector4 { - #[inline] - fn into(self) -> Simdu32x4 { - let self_ref: &[u32; 4] = self.as_ref(); - Simdu32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdu32x4]; Add> for Vector4 { - fn add(lhs, rhs) -> Vector4 { - (lhs + rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdu32x4]; Sub> for Vector4 { - fn sub(lhs, rhs) -> Vector4 { - (lhs - rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdu32x4]; Mul for Vector4 { - fn mul(lhs, rhs) -> Vector4 { - (lhs * rhs).into() - } - } -} - -#[cfg(feature = "simd")] -impl AddAssign for Vector4 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdu32x4 = (*self).into(); - let rhs: Simdu32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl SubAssign for Vector4 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdu32x4 = (*self).into(); - let rhs: Simdu32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(feature = "simd")] -impl MulAssign for Vector4 { - fn mul_assign(&mut self, other: u32) { - let s: Simdu32x4 = (*self).into(); - let other = Simdu32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(feature = "mint")] -impl_mint_conversions!(Vector2 { x, y }, Vector2); -#[cfg(feature = "mint")] -impl_mint_conversions!(Vector3 { x, y, z }, Vector3); -#[cfg(feature = "mint")] -impl_mint_conversions!(Vector4 { x, y, z, w }, Vector4); - -#[cfg(test)] -mod tests { - mod vector2 { - use vector::*; - - const VECTOR2: Vector2 = Vector2 { x: 1, y: 2 }; - - #[test] - fn test_index() { - assert_eq!(VECTOR2[0], VECTOR2.x); - assert_eq!(VECTOR2[1], VECTOR2.y); - } - - #[test] - fn test_index_mut() { - let mut v = VECTOR2; - *&mut v[0] = 0; - assert_eq!(v, [0, 2].into()); - } - - #[test] - #[should_panic] - fn test_index_out_of_bounds() { - VECTOR2[2]; - } - - #[test] - fn test_index_range() { - assert_eq!(&VECTOR2[..0], &[]); - assert_eq!(&VECTOR2[..1], &[1]); - assert_eq!(VECTOR2[..0].len(), 0); - assert_eq!(VECTOR2[..1].len(), 1); - assert_eq!(&VECTOR2[2..], &[]); - assert_eq!(&VECTOR2[1..], &[2]); - assert_eq!(VECTOR2[2..].len(), 0); - assert_eq!(VECTOR2[1..].len(), 1); - assert_eq!(&VECTOR2[..], &[1, 2]); - assert_eq!(VECTOR2[..].len(), 2); - } - - #[test] - fn test_into() { - let v = VECTOR2; - { - let v: [i32; 2] = v.into(); - assert_eq!(v, [1, 2]); - } - { - let v: (i32, i32) = v.into(); - assert_eq!(v, (1, 2)); - } - } - - #[test] - fn test_as_ref() { - let v = VECTOR2; - { - let v: &[i32; 2] = v.as_ref(); - assert_eq!(v, &[1, 2]); - } - { - let v: &(i32, i32) = v.as_ref(); - assert_eq!(v, &(1, 2)); - } - } - - #[test] - fn test_as_mut() { - let mut v = VECTOR2; - { - let v: &mut [i32; 2] = v.as_mut(); - assert_eq!(v, &mut [1, 2]); - } - { - let v: &mut (i32, i32) = v.as_mut(); - assert_eq!(v, &mut (1, 2)); - } - } - - #[test] - fn test_from() { - assert_eq!(Vector2::from([1, 2]), VECTOR2); - { - let v = &[1, 2]; - let v: &Vector2<_> = From::from(v); - assert_eq!(v, &VECTOR2); - } - { - let v = &mut [1, 2]; - let v: &mut Vector2<_> = From::from(v); - assert_eq!(v, &VECTOR2); - } - assert_eq!(Vector2::from((1, 2)), VECTOR2); - { - let v = &(1, 2); - let v: &Vector2<_> = From::from(v); - assert_eq!(v, &VECTOR2); - } - { - let v = &mut (1, 2); - let v: &mut Vector2<_> = From::from(v); - assert_eq!(v, &VECTOR2); - } - } - - #[test] - fn test_is_finite() { - use num_traits::Float; - assert!(!Vector2::from([Float::nan(), 1.0]).is_finite()); - assert!(!Vector2::from([1.0, Float::infinity()]).is_finite()); - assert!(Vector2::from([-1.0, 1.0]).is_finite()); - } - } - - mod vector3 { - use vector::*; - - const VECTOR3: Vector3 = Vector3 { x: 1, y: 2, z: 3 }; - - #[test] - fn test_index() { - assert_eq!(VECTOR3[0], VECTOR3.x); - assert_eq!(VECTOR3[1], VECTOR3.y); - assert_eq!(VECTOR3[2], VECTOR3.z); - } - - #[test] - fn test_index_mut() { - let mut v = VECTOR3; - *&mut v[1] = 0; - assert_eq!(v, [1, 0, 3].into()); - } - - #[test] - #[should_panic] - fn test_index_out_of_bounds() { - VECTOR3[3]; - } - - #[test] - fn test_index_range() { - assert_eq!(&VECTOR3[..1], &[1]); - assert_eq!(&VECTOR3[..2], &[1, 2]); - assert_eq!(VECTOR3[..1].len(), 1); - assert_eq!(VECTOR3[..2].len(), 2); - assert_eq!(&VECTOR3[2..], &[3]); - assert_eq!(&VECTOR3[1..], &[2, 3]); - assert_eq!(VECTOR3[2..].len(), 1); - assert_eq!(VECTOR3[1..].len(), 2); - assert_eq!(&VECTOR3[..], &[1, 2, 3]); - assert_eq!(VECTOR3[..].len(), 3); - } - - #[test] - fn test_into() { - let v = VECTOR3; - { - let v: [i32; 3] = v.into(); - assert_eq!(v, [1, 2, 3]); - } - { - let v: (i32, i32, i32) = v.into(); - assert_eq!(v, (1, 2, 3)); - } - } - - #[test] - fn test_as_ref() { - let v = VECTOR3; - { - let v: &[i32; 3] = v.as_ref(); - assert_eq!(v, &[1, 2, 3]); - } - { - let v: &(i32, i32, i32) = v.as_ref(); - assert_eq!(v, &(1, 2, 3)); - } - } - - #[test] - fn test_as_mut() { - let mut v = VECTOR3; - { - let v: &mut [i32; 3] = v.as_mut(); - assert_eq!(v, &mut [1, 2, 3]); - } - { - let v: &mut (i32, i32, i32) = v.as_mut(); - assert_eq!(v, &mut (1, 2, 3)); - } - } - - #[test] - fn test_from() { - assert_eq!(Vector3::from([1, 2, 3]), VECTOR3); - { - let v = &[1, 2, 3]; - let v: &Vector3<_> = From::from(v); - assert_eq!(v, &VECTOR3); - } - { - let v = &mut [1, 2, 3]; - let v: &mut Vector3<_> = From::from(v); - assert_eq!(v, &VECTOR3); - } - assert_eq!(Vector3::from((1, 2, 3)), VECTOR3); - { - let v = &(1, 2, 3); - let v: &Vector3<_> = From::from(v); - assert_eq!(v, &VECTOR3); - } - { - let v = &mut (1, 2, 3); - let v: &mut Vector3<_> = From::from(v); - assert_eq!(v, &VECTOR3); - } - } - - #[test] - fn test_is_finite() { - use num_traits::Float; - assert!(!Vector3::from([Float::nan(), 1.0, 1.0]).is_finite()); - assert!(!Vector3::from([1.0, 1.0, Float::infinity()]).is_finite()); - assert!(Vector3::from([-1.0, 1.0, 1.0]).is_finite()); - } - } - - mod vector4 { - use vector::*; - - const VECTOR4: Vector4 = Vector4 { - x: 1, - y: 2, - z: 3, - w: 4, - }; - - #[test] - fn test_index() { - assert_eq!(VECTOR4[0], VECTOR4.x); - assert_eq!(VECTOR4[1], VECTOR4.y); - assert_eq!(VECTOR4[2], VECTOR4.z); - assert_eq!(VECTOR4[3], VECTOR4.w); - } - - #[test] - fn test_index_mut() { - let mut v = VECTOR4; - *&mut v[2] = 0; - assert_eq!(v, [1, 2, 0, 4].into()); - } - - #[test] - #[should_panic] - fn test_index_out_of_bounds() { - VECTOR4[4]; - } - - #[test] - fn test_index_range() { - assert_eq!(&VECTOR4[..2], &[1, 2]); - assert_eq!(&VECTOR4[..3], &[1, 2, 3]); - assert_eq!(VECTOR4[..2].len(), 2); - assert_eq!(VECTOR4[..3].len(), 3); - assert_eq!(&VECTOR4[2..], &[3, 4]); - assert_eq!(&VECTOR4[1..], &[2, 3, 4]); - assert_eq!(VECTOR4[2..].len(), 2); - assert_eq!(VECTOR4[1..].len(), 3); - assert_eq!(&VECTOR4[..], &[1, 2, 3, 4]); - assert_eq!(VECTOR4[..].len(), 4); - } - - #[test] - fn test_into() { - let v = VECTOR4; - { - let v: [i32; 4] = v.into(); - assert_eq!(v, [1, 2, 3, 4]); - } - { - let v: (i32, i32, i32, i32) = v.into(); - assert_eq!(v, (1, 2, 3, 4)); - } - } - - #[test] - fn test_as_ref() { - let v = VECTOR4; - { - let v: &[i32; 4] = v.as_ref(); - assert_eq!(v, &[1, 2, 3, 4]); - } - { - let v: &(i32, i32, i32, i32) = v.as_ref(); - assert_eq!(v, &(1, 2, 3, 4)); - } - } - - #[test] - fn test_as_mut() { - let mut v = VECTOR4; - { - let v: &mut [i32; 4] = v.as_mut(); - assert_eq!(v, &mut [1, 2, 3, 4]); - } - { - let v: &mut (i32, i32, i32, i32) = v.as_mut(); - assert_eq!(v, &mut (1, 2, 3, 4)); - } - } - - #[test] - fn test_from() { - assert_eq!(Vector4::from([1, 2, 3, 4]), VECTOR4); - { - let v = &[1, 2, 3, 4]; - let v: &Vector4<_> = From::from(v); - assert_eq!(v, &VECTOR4); - } - { - let v = &mut [1, 2, 3, 4]; - let v: &mut Vector4<_> = From::from(v); - assert_eq!(v, &VECTOR4); - } - assert_eq!(Vector4::from((1, 2, 3, 4)), VECTOR4); - { - let v = &(1, 2, 3, 4); - let v: &Vector4<_> = From::from(v); - assert_eq!(v, &VECTOR4); - } - { - let v = &mut (1, 2, 3, 4); - let v: &mut Vector4<_> = From::from(v); - assert_eq!(v, &VECTOR4); - } - } - - #[test] - fn test_is_finite() { - use num_traits::Float; - assert!(!Vector4::from([0.0, Float::nan(), 1.0, 1.0]).is_finite()); - assert!(!Vector4::from([1.0, 1.0, Float::neg_infinity(), 0.0]).is_finite()); - assert!(Vector4::from([-1.0, 0.0, 1.0, 1.0]).is_finite()); - } - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/matrix.rs b/third_party/cargo/vendor/cgmath-0.17.0/tests/matrix.rs deleted file mode 100755 index 80f1152..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/matrix.rs +++ /dev/null @@ -1,784 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[macro_use] -extern crate approx; -extern crate cgmath; - -pub mod matrix2 { - use std::f64; - - use cgmath::*; - - const A: Matrix2 = Matrix2 { x: Vector2 { x: 1.0f64, y: 3.0f64 }, - y: Vector2 { x: 2.0f64, y: 4.0f64 } }; - const B: Matrix2 = Matrix2 { x: Vector2 { x: 2.0f64, y: 4.0f64 }, - y: Vector2 { x: 3.0f64, y: 5.0f64 } }; - const C: Matrix2 = Matrix2 { x: Vector2 { x: 2.0f64, y: 1.0f64 }, - y: Vector2 { x: 1.0f64, y: 2.0f64 } }; - - const V: Vector2 = Vector2 { x: 1.0f64, y: 2.0f64 }; - const F: f64 = 0.5; - - #[test] - fn test_neg() { - assert_eq!(-A, - Matrix2::new(-1.0f64, -3.0f64, - -2.0f64, -4.0f64)); - } - - #[test] - fn test_mul_scalar() { - let result = Matrix2::new(0.5f64, 1.5f64, - 1.0f64, 2.0f64) ; - assert_eq!(A * F, result); - assert_eq!(F * A, result); - } - - #[test] - fn test_div_scalar() { - assert_eq!(A / F, - Matrix2::new(2.0f64, 6.0f64, - 4.0f64, 8.0f64)); - assert_eq!(4.0f64 / C, - Matrix2::new(2.0f64, 4.0f64, - 4.0f64, 2.0f64)); - } - - #[test] - fn test_rem_scalar() { - assert_eq!(A % 3.0f64, - Matrix2::new(1.0f64, 0.0f64, - 2.0f64, 1.0f64)); - assert_eq!(3.0f64 % A, - Matrix2::new(0.0f64, 0.0f64, - 1.0f64, 3.0f64)); - } - - #[test] - fn test_add_matrix() { - assert_eq!(A + B, - Matrix2::new(3.0f64, 7.0f64, - 5.0f64, 9.0f64)); - } - - #[test] - fn test_sub_matrix() { - assert_eq!(A - B, - Matrix2::new(-1.0f64, -1.0f64, - -1.0f64, -1.0f64)); - } - - #[test] - fn test_mul_vector() { - assert_eq!(A * V, Vector2::new(5.0f64, 11.0f64)); - } - - #[test] - fn test_mul_matrix() { - assert_eq!(A * B, - Matrix2::new(10.0f64, 22.0f64, - 13.0f64, 29.0f64)); - - assert_eq!(A * B, &A * &B); - } - - #[test] - fn test_sum_matrix() { - assert_eq!(A + B + C, [A, B, C].iter().sum()); - assert_eq!(A + B + C, [A, B, C].iter().cloned().sum()); - } - - #[test] - fn test_product_matrix() { - assert_eq!(A * B * C, [A, B, C].iter().product()); - assert_eq!(A * B * C, [A, B, C].iter().cloned().product()); - } - - #[test] - fn test_determinant() { - assert_eq!(A.determinant(), -2.0f64) - } - - #[test] - fn test_trace() { - assert_eq!(A.trace(), 5.0f64); - } - - #[test] - fn test_transpose() { - assert_eq!(A.transpose(), - Matrix2::::new(1.0f64, 2.0f64, - 3.0f64, 4.0f64)); - } - - #[test] - fn test_transpose_self() { - let mut mut_a = A; - mut_a.transpose_self(); - assert_eq!(mut_a, A.transpose()); - } - - #[test] - fn test_invert() { - assert!(Matrix2::::identity().invert().unwrap().is_identity()); - - assert_eq!(A.invert().unwrap(), - Matrix2::new(-2.0f64, 1.5f64, - 1.0f64, -0.5f64)); - assert!(Matrix2::new(0.0f64, 2.0f64, - 0.0f64, 5.0f64).invert().is_none()); - } - - #[test] - fn test_predicates() { - assert!(Matrix2::::identity().is_identity()); - assert!(Matrix2::::identity().is_symmetric()); - assert!(Matrix2::::identity().is_diagonal()); - assert!(Matrix2::::identity().is_invertible()); - - assert!(!A.is_identity()); - assert!(!A.is_symmetric()); - assert!(!A.is_diagonal()); - assert!(A.is_invertible()); - - assert!(!C.is_identity()); - assert!(C.is_symmetric()); - assert!(!C.is_diagonal()); - assert!(C.is_invertible()); - - assert!(Matrix2::from_value(6.0f64).is_diagonal()); - } - - #[test] - fn test_from_angle() { - // Rotate the vector (1, 0) by π/2 radians to the vector (0, 1) - let rot1 = Matrix2::from_angle(Rad(0.5f64 * f64::consts::PI)); - assert_ulps_eq!(rot1 * Vector2::unit_x(), &Vector2::unit_y()); - - // Rotate the vector (-1, 0) by -π/2 radians to the vector (0, 1) - let rot2 = -rot1; - assert_ulps_eq!(rot2 * -Vector2::unit_x(), &Vector2::unit_y()); - - // Rotate the vector (1, 1) by π radians to the vector (-1, -1) - let rot3: Matrix2 = Matrix2::from_angle(Rad(f64::consts::PI)); - assert_ulps_eq!(rot3 * Vector2::new(1.0, 1.0), &Vector2::new(-1.0, -1.0)); - } -} - -pub mod matrix3 { - use cgmath::*; - - const A: Matrix3 = Matrix3 { x: Vector3 { x: 1.0f64, y: 4.0f64, z: 7.0f64 }, - y: Vector3 { x: 2.0f64, y: 5.0f64, z: 8.0f64 }, - z: Vector3 { x: 3.0f64, y: 6.0f64, z: 9.0f64 } }; - const B: Matrix3 = Matrix3 { x: Vector3 { x: 2.0f64, y: 5.0f64, z: 8.0f64 }, - y: Vector3 { x: 3.0f64, y: 6.0f64, z: 9.0f64 }, - z: Vector3 { x: 4.0f64, y: 7.0f64, z: 10.0f64 } }; - const C: Matrix3 = Matrix3 { x: Vector3 { x: 2.0f64, y: 4.0f64, z: 6.0f64 }, - y: Vector3 { x: 0.0f64, y: 2.0f64, z: 4.0f64 }, - z: Vector3 { x: 0.0f64, y: 0.0f64, z: 1.0f64 } }; - const D: Matrix3 = Matrix3 { x: Vector3 { x: 3.0f64, y: 2.0f64, z: 1.0f64 }, - y: Vector3 { x: 2.0f64, y: 3.0f64, z: 2.0f64 }, - z: Vector3 { x: 1.0f64, y: 2.0f64, z: 3.0f64 } }; - - const V: Vector3 = Vector3 { x: 1.0f64, y: 2.0f64, z: 3.0f64 }; - const F: f64 = 0.5; - - #[test] - fn test_neg() { - assert_eq!(-A, - Matrix3::new(-1.0f64, -4.0f64, -7.0f64, - -2.0f64, -5.0f64, -8.0f64, - -3.0f64, -6.0f64, -9.0f64)); - } - - #[test] - fn test_mul_scalar() { - let result = Matrix3::new(0.5f64, 2.0f64, 3.5f64, - 1.0f64, 2.5f64, 4.0f64, - 1.5f64, 3.0f64, 4.5f64); - assert_eq!(A * F, result); - assert_eq!(F * A, result); - } - - #[test] - fn test_div_scalar() { - assert_eq!(A / F, - Matrix3::new(2.0f64, 8.0f64, 14.0f64, - 4.0f64, 10.0f64, 16.0f64, - 6.0f64, 12.0f64, 18.0f64)); - assert_eq!(6.0f64 / D, - Matrix3::new(2.0f64, 3.0f64, 6.0f64, - 3.0f64, 2.0f64, 3.0f64, - 6.0f64, 3.0f64, 2.0f64)); - } - - #[test] - fn test_rem_scalar() { - assert_eq!(A % 3.0f64, - Matrix3::new(1.0f64, 1.0f64, 1.0f64, - 2.0f64, 2.0f64, 2.0f64, - 0.0f64, 0.0f64, 0.0f64)); - assert_eq!(9.0f64 % A, - Matrix3::new(0.0f64, 1.0f64, 2.0f64, - 1.0f64, 4.0f64, 1.0f64, - 0.0f64, 3.0f64, 0.0f64)); - } - - #[test] - fn test_add_matrix() { - assert_eq!(A + B, - Matrix3::new(3.0f64, 9.0f64, 15.0f64, - 5.0f64, 11.0f64, 17.0f64, - 7.0f64, 13.0f64, 19.0f64)); - } - - #[test] - fn test_sub_matrix() { - assert_eq!(A - B, - Matrix3::new(-1.0f64, -1.0f64, -1.0f64, - -1.0f64, -1.0f64, -1.0f64, - -1.0f64, -1.0f64, -1.0f64)); - } - - #[test] - fn test_mul_vector() { - assert_eq!(A * V, Vector3::new(14.0f64, 32.0f64, 50.0f64)); - } - - #[test] - fn test_mul_matrix() { - assert_eq!(A * B, - Matrix3::new(36.0f64, 81.0f64, 126.0f64, - 42.0f64, 96.0f64, 150.0f64, - 48.0f64, 111.0f64, 174.0f64)); - - assert_eq!(A * B, &A * &B); - } - - #[test] - fn test_sum_matrix() { - assert_eq!(A + B + C + D, [A, B, C, D].iter().sum()); - assert_eq!(A + B + C + D, [A, B, C, D].iter().cloned().sum()); - } - - #[test] - fn test_product_matrix() { - assert_eq!(A * B * C * D, [A, B, C, D].iter().product()); - assert_eq!(A * B * C * D, [A, B, C, D].iter().cloned().product()); - } - - #[test] - fn test_determinant() {; - assert_eq!(A.determinant(), 0.0f64); - } - - #[test] - fn test_trace() { - assert_eq!(A.trace(), 15.0f64); - } - - #[test] - fn test_transpose() { - assert_eq!(A.transpose(), - Matrix3::::new(1.0f64, 2.0f64, 3.0f64, - 4.0f64, 5.0f64, 6.0f64, - 7.0f64, 8.0f64, 9.0f64)); - } - - #[test] - fn test_transpose_self() { - let mut mut_a = A; - mut_a.transpose_self(); - assert_eq!(mut_a, A.transpose()); - } - - #[test] - fn test_invert() { - assert!(Matrix3::::identity().invert().unwrap().is_identity()); - - assert_eq!(A.invert(), None); - - assert_eq!(C.invert().unwrap(), - Matrix3::new(0.5f64, -1.0f64, 1.0f64, - 0.0f64, 0.5f64, -2.0f64, - 0.0f64, 0.0f64, 1.0f64)); - } - - #[test] - fn test_predicates() { - assert!(Matrix3::::identity().is_identity()); - assert!(Matrix3::::identity().is_symmetric()); - assert!(Matrix3::::identity().is_diagonal()); - assert!(Matrix3::::identity().is_invertible()); - - assert!(!A.is_identity()); - assert!(!A.is_symmetric()); - assert!(!A.is_diagonal()); - assert!(!A.is_invertible()); - - assert!(!D.is_identity()); - assert!(D.is_symmetric()); - assert!(!D.is_diagonal()); - assert!(D.is_invertible()); - - assert!(Matrix3::from_value(6.0f64).is_diagonal()); - } - - mod from_axis_x { - use cgmath::*; - - fn check_from_axis_angle_x(pitch: Rad) { - let found = Matrix3::from_angle_x(pitch); - let expected = Matrix3::from(Euler { x: pitch, y: Rad(0.0), z: Rad(0.0) }); - assert_relative_eq!(found, expected, epsilon = 0.001); - } - - #[test] fn test_zero() { check_from_axis_angle_x(Rad(0.0)); } - #[test] fn test_pos_1() { check_from_axis_angle_x(Rad(1.0)); } - #[test] fn test_neg_1() { check_from_axis_angle_x(Rad(-1.0)); } - } - - mod from_axis_y { - use cgmath::*; - - fn check_from_axis_angle_y(yaw: Rad) { - let found = Matrix3::from_angle_y(yaw); - let expected = Matrix3::from(Euler { x: Rad(0.0), y: yaw, z: Rad(0.0) }); - assert_relative_eq!(found, expected, epsilon = 0.001); - } - - #[test] fn test_zero() { check_from_axis_angle_y(Rad(0.0)); } - #[test] fn test_pos_1() { check_from_axis_angle_y(Rad(1.0)); } - #[test] fn test_neg_1() { check_from_axis_angle_y(Rad(-1.0)); } - } - - mod from_axis_z { - use cgmath::*; - - fn check_from_axis_angle_z(roll: Rad) { - let found = Matrix3::from_angle_z(roll); - let expected = Matrix3::from(Euler { x: Rad(0.0), y: Rad(0.0), z: roll }); - assert_relative_eq!(found, expected, epsilon = 0.001); - } - - #[test] fn test_zero() { check_from_axis_angle_z(Rad(0.0)); } - #[test] fn test_pos_1() { check_from_axis_angle_z(Rad(1.0)); } - #[test] fn test_neg_1() { check_from_axis_angle_z(Rad(-1.0)); } - } - - mod from_axis_angle { - mod axis_x { - use cgmath::*; - - fn check_from_axis_angle_x(pitch: Rad) { - let found = Matrix3::from_axis_angle(Vector3::unit_x(), pitch); - let expected = Matrix3::from(Euler { x: pitch, y: Rad(0.0), z: Rad(0.0) }); - assert_relative_eq!(found, expected, epsilon = 0.001); - } - - #[test] fn test_zero() { check_from_axis_angle_x(Rad(0.0)); } - #[test] fn test_pos_1() { check_from_axis_angle_x(Rad(1.0)); } - #[test] fn test_neg_1() { check_from_axis_angle_x(Rad(-1.0)); } - } - - mod axis_y { - use cgmath::*; - - fn check_from_axis_angle_y(yaw: Rad) { - let found = Matrix3::from_axis_angle(Vector3::unit_y(), yaw); - let expected = Matrix3::from(Euler { x: Rad(0.0), y: yaw, z: Rad(0.0) }); - assert_relative_eq!(found, expected, epsilon = 0.001); - } - - #[test] fn test_zero() { check_from_axis_angle_y(Rad(0.0)); } - #[test] fn test_pos_1() { check_from_axis_angle_y(Rad(1.0)); } - #[test] fn test_neg_1() { check_from_axis_angle_y(Rad(-1.0)); } - } - - mod axis_z { - use cgmath::*; - - fn check_from_axis_angle_z(roll: Rad) { - let found = Matrix3::from_axis_angle(Vector3::unit_z(), roll); - let expected = Matrix3::from(Euler { x: Rad(0.0), y: Rad(0.0), z: roll }); - assert_relative_eq!(found, expected, epsilon = 0.001); - } - - #[test] fn test_zero() { check_from_axis_angle_z(Rad(0.0)); } - #[test] fn test_pos_1() { check_from_axis_angle_z(Rad(1.0)); } - #[test] fn test_neg_1() { check_from_axis_angle_z(Rad(-1.0)); } - } - } - - mod rotate_from_euler { - use cgmath::*; - - #[test] - fn test_x() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Matrix3::from(Euler::new(Deg(90.0), Deg(0.0), Deg(0.0))); - assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); - - let rot = Matrix3::from(Euler::new(Deg(-90.0), Deg(0.0), Deg(0.0))); - assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); - } - - #[test] - fn test_y() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(90.0), Deg(0.0))); - assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); - - let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(-90.0), Deg(0.0))); - assert_ulps_eq!(vec3(-1.0, 0.0, 0.0), rot * vec); - } - - #[test] - fn test_z() { - let vec = vec3(1.0, 0.0, 0.0); - - let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(0.0), Deg(90.0))); - assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); - - let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(0.0), Deg(-90.0))); - assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); - } - - - // tests that the Y rotation is done after the X - #[test] - fn test_x_then_y() { - let vec = vec3(0.0, 1.0, 0.0); - - let rot = Matrix3::from(Euler::new(Deg(90.0), Deg(90.0), Deg(0.0))); - assert_ulps_eq!(vec3(0.0, 0.0, 1.0), rot * vec); - } - - // tests that the Z rotation is done after the Y - #[test] - fn test_y_then_z() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(90.0), Deg(90.0))); - assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); - } - } - - mod rotate_from_axis_angle { - use cgmath::*; - - #[test] - fn test_x() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Matrix3::from_angle_x(Deg(90.0)); - println!("x mat: {:?}", rot); - assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); - } - - #[test] - fn test_y() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Matrix3::from_angle_y(Deg(90.0)); - assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); - } - - #[test] - fn test_z() { - let vec = vec3(1.0, 0.0, 0.0); - - let rot = Matrix3::from_angle_z(Deg(90.0)); - assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); - } - - #[test] - fn test_xy() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Matrix3::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), Deg(90.0)); - assert_ulps_eq!(vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0), rot * vec); - } - - #[test] - fn test_yz() { - let vec = vec3(1.0, 0.0, 0.0); - - let rot = Matrix3::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), Deg(-90.0)); - assert_ulps_eq!(vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0), rot * vec); - } - - #[test] - fn test_xz() { - let vec = vec3(0.0, 1.0, 0.0); - - let rot = Matrix3::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), Deg(90.0)); - assert_ulps_eq!(vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), rot * vec); - } - } -} - -pub mod matrix4 { - use cgmath::*; - - const A: Matrix4 = Matrix4 { x: Vector4 { x: 1.0f64, y: 5.0f64, z: 9.0f64, w: 13.0f64 }, - y: Vector4 { x: 2.0f64, y: 6.0f64, z: 10.0f64, w: 14.0f64 }, - z: Vector4 { x: 3.0f64, y: 7.0f64, z: 11.0f64, w: 15.0f64 }, - w: Vector4 { x: 4.0f64, y: 8.0f64, z: 12.0f64, w: 16.0f64 } }; - const B: Matrix4 = Matrix4 { x: Vector4 { x: 2.0f64, y: 6.0f64, z: 10.0f64, w: 14.0f64 }, - y: Vector4 { x: 3.0f64, y: 7.0f64, z: 11.0f64, w: 15.0f64 }, - z: Vector4 { x: 4.0f64, y: 8.0f64, z: 12.0f64, w: 16.0f64 }, - w: Vector4 { x: 5.0f64, y: 9.0f64, z: 13.0f64, w: 17.0f64 } }; - const C: Matrix4 = Matrix4 { x: Vector4 { x: 3.0f64, y: 2.0f64, z: 1.0f64, w: 1.0f64 }, - y: Vector4 { x: 2.0f64, y: 3.0f64, z: 2.0f64, w: 2.0f64 }, - z: Vector4 { x: 1.0f64, y: 2.0f64, z: 3.0f64, w: 3.0f64 }, - w: Vector4 { x: 0.0f64, y: 1.0f64, z: 1.0f64, w: 0.0f64 } }; - const D: Matrix4 = Matrix4 { x: Vector4 { x: 4.0f64, y: 3.0f64, z: 2.0f64, w: 1.0f64 }, - y: Vector4 { x: 3.0f64, y: 4.0f64, z: 3.0f64, w: 2.0f64 }, - z: Vector4 { x: 2.0f64, y: 3.0f64, z: 4.0f64, w: 3.0f64 }, - w: Vector4 { x: 1.0f64, y: 2.0f64, z: 3.0f64, w: 4.0f64 } }; - - const V: Vector4 = Vector4 { x: 1.0f64, y: 2.0f64, z: 3.0f64, w: 4.0f64 }; - const F: f64 = 0.5; - - #[test] - fn test_neg() { - assert_eq!(-A, - Matrix4::new(-1.0f64, -5.0f64, -9.0f64, -13.0f64, - -2.0f64, -6.0f64, -10.0f64, -14.0f64, - -3.0f64, -7.0f64, -11.0f64, -15.0f64, - -4.0f64, -8.0f64, -12.0f64, -16.0f64)); - } - - #[test] - fn test_mul_scalar() { - let result = Matrix4::new(0.5f64, 2.5f64, 4.5f64, 6.5f64, - 1.0f64, 3.0f64, 5.0f64, 7.0f64, - 1.5f64, 3.5f64, 5.5f64, 7.5f64, - 2.0f64, 4.0f64, 6.0f64, 8.0f64); - assert_eq!(A * F, result); - assert_eq!(F * A, result); - } - - #[test] - fn test_div_scalar() { - assert_eq!(A / F, - Matrix4::new(2.0f64, 10.0f64, 18.0f64, 26.0f64, - 4.0f64, 12.0f64, 20.0f64, 28.0f64, - 6.0f64, 14.0f64, 22.0f64, 30.0f64, - 8.0f64, 16.0f64, 24.0f64, 32.0f64)); - assert_eq!(12.0f64 / D, - Matrix4::new( 3.0f64, 4.0f64, 6.0f64, 12.0f64, - 4.0f64, 3.0f64, 4.0f64, 6.0f64, - 6.0f64, 4.0f64, 3.0f64, 4.0f64, - 12.0f64, 6.0f64, 4.0f64, 3.0f64)); - } - - #[test] - fn test_rem_scalar() { - assert_eq!(A % 4.0f64, - Matrix4::new(1.0f64, 1.0f64, 1.0f64, 1.0f64, - 2.0f64, 2.0f64, 2.0f64, 2.0f64, - 3.0f64, 3.0f64, 3.0f64, 3.0f64, - 0.0f64, 0.0f64, 0.0f64, 0.0f64)); - assert_eq!(16.0f64 % A, - Matrix4::new(0.0f64, 1.0f64, 7.0f64, 3.0f64, - 0.0f64, 4.0f64, 6.0f64, 2.0f64, - 1.0f64, 2.0f64, 5.0f64, 1.0f64, - 0.0f64, 0.0f64, 4.0f64, 0.0f64)); - } - - #[test] - fn test_add_matrix() { - assert_eq!(A + B, - Matrix4::new(3.0f64, 11.0f64, 19.0f64, 27.0f64, - 5.0f64, 13.0f64, 21.0f64, 29.0f64, - 7.0f64, 15.0f64, 23.0f64, 31.0f64, - 9.0f64, 17.0f64, 25.0f64, 33.0f64)); - } - - #[test] - fn test_sub_matrix() { - assert_eq!(A - B, - Matrix4::new(-1.0f64, -1.0f64, -1.0f64, -1.0f64, - -1.0f64, -1.0f64, -1.0f64, -1.0f64, - -1.0f64, -1.0f64, -1.0f64, -1.0f64, - -1.0f64, -1.0f64, -1.0f64, -1.0f64)); - } - - #[test] - fn test_mul_vector() { - assert_eq!(A * V, Vector4::new(30.0f64, 70.0f64, 110.0f64, 150.0f64)); - } - - #[test] - fn test_mul_matrix() { - assert_eq!(A * B, - Matrix4::new(100.0f64, 228.0f64, 356.0f64, 484.0f64, - 110.0f64, 254.0f64, 398.0f64, 542.0f64, - 120.0f64, 280.0f64, 440.0f64, 600.0f64, - 130.0f64, 306.0f64, 482.0f64, 658.0f64)); - - assert_eq!(A * B, &A * &B); - } - - #[test] - fn test_sum_matrix() { - assert_eq!(A + B + C + D, [A, B, C, D].iter().sum()); - assert_eq!(A + B + C + D, [A, B, C, D].iter().cloned().sum()); - } - - #[test] - fn test_product_matrix() { - assert_eq!(A * B * C * D, [A, B, C, D].iter().product()); - assert_eq!(A * B * C * D, [A, B, C, D].iter().cloned().product()); - } - - #[test] - fn test_determinant() { - assert_eq!(A.determinant(), 0.0f64); - } - - #[test] - fn test_trace() { - assert_eq!(A.trace(), 34.0f64); - } - - #[test] - fn test_transpose() { - assert_eq!(A.transpose(), - Matrix4::::new( 1.0f64, 2.0f64, 3.0f64, 4.0f64, - 5.0f64, 6.0f64, 7.0f64, 8.0f64, - 9.0f64, 10.0f64, 11.0f64, 12.0f64, - 13.0f64, 14.0f64, 15.0f64, 16.0f64)); - } - - #[test] - fn test_transpose_self() { - let mut mut_a = A; - mut_a.transpose_self(); - assert_eq!(mut_a, A.transpose()); - } - - #[test] - fn test_invert() { - assert!(Matrix4::::identity().invert().unwrap().is_identity()); - - assert_ulps_eq!(&C.invert().unwrap(), &( - Matrix4::new( 5.0f64, -4.0f64, 1.0f64, 0.0f64, - -4.0f64, 8.0f64, -4.0f64, 0.0f64, - 4.0f64, -8.0f64, 4.0f64, 8.0f64, - -3.0f64, 4.0f64, 1.0f64, -8.0f64) * 0.125f64)); - - let mat_c = Matrix4::new(-0.131917f64, -0.76871f64, 0.625846f64, 0.0f64, - -0., 0.631364f64, 0.775487f64, 0.0f64, - -0.991261f64, 0.1023f64, -0.083287f64, 0.0f64, - 0., -1.262728f64, -1.550973f64, 1.0f64); - assert!((mat_c.invert().unwrap() * mat_c).is_identity()); - - let mat_d = Matrix4::new( 0.065455f64, -0.720002f64, 0.690879f64, 0.0f64, - -0., 0.692364f64, 0.721549f64, 0.0f64, - -0.997856f64, -0.047229f64, 0.045318f64, 0.0f64, - 0., -1.384727f64, -1.443098f64, 1.0f64); - assert!((mat_d.invert().unwrap() * mat_d).is_identity()); - - let mat_e = Matrix4::new( 0.409936f64, 0.683812f64, -0.603617f64, 0.0f64, - 0., 0.661778f64, 0.7497f64, 0.0f64, - 0.912114f64, -0.307329f64, 0.271286f64, 0.0f64, - -0., -1.323555f64, -1.499401f64, 1.0f64); - assert!((mat_e.invert().unwrap() * mat_e).is_identity()); - - let mat_f = Matrix4::new(-0.160691f64, -0.772608f64, 0.614211f64, 0.0f64, - -0., 0.622298f64, 0.78278f64, 0.0f64, - -0.987005f64, 0.125786f64, -0.099998f64, 0.0f64, - 0., -1.244597f64, -1.565561f64, 1.0f64); - assert!((mat_f.invert().unwrap() * mat_f).is_identity()); - } - - #[test] - fn test_predicates() { - assert!(Matrix4::::identity().is_identity()); - assert!(Matrix4::::identity().is_symmetric()); - assert!(Matrix4::::identity().is_diagonal()); - assert!(Matrix4::::identity().is_invertible()); - - assert!(!A.is_identity()); - assert!(!A.is_symmetric()); - assert!(!A.is_diagonal()); - assert!(!A.is_invertible()); - - assert!(!D.is_identity()); - assert!(D.is_symmetric()); - assert!(!D.is_diagonal()); - assert!(D.is_invertible()); - - assert!(Matrix4::from_value(6.0f64).is_diagonal()); - } - - #[test] - fn test_from_translation() { - let mat = Matrix4::from_translation(Vector3::new(1.0f64, 2.0f64, 3.0f64)); - let vertex = Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64); - let res = mat * vertex; - assert_eq!(res, Vector4::new(1., 2., 3., 1.)); - } - - #[test] - fn test_cast() { - assert_ulps_eq!(Matrix2::new(0.2f64, 1.5, 4.7, 2.3).cast().unwrap(), Matrix2::new(0.2f32, 1.5, 4.7, 2.3)); - assert_ulps_eq!(Matrix3::new( - 0.2f64, 1.5, 4.7, - 2.3, 5.7, 2.1, - 4.6, 5.2, 6.6, - ).cast().unwrap(), Matrix3::new( - 0.2f32, 1.5, 4.7, - 2.3, 5.7, 2.1, - 4.6, 5.2, 6.6, - )); - - assert_ulps_eq!(Matrix4::new( - 0.2f64, 1.5, 4.7, 2.5, - 2.3, 5.7, 2.1, 1.1, - 4.6, 5.2, 6.6, 0.2, - 3.2, 1.8, 0.4, 2.9, - ).cast().unwrap(), Matrix4::new( - 0.2f32, 1.5, 4.7, 2.5, - 2.3, 5.7, 2.1, 1.1, - 4.6, 5.2, 6.6, 0.2, - 3.2, 1.8, 0.4, 2.9, - )); - - } - - mod from { - use cgmath::*; - - #[test] - fn test_quaternion() { - let quaternion = Quaternion::new(2f32, 3f32, 4f32, 5f32); - - let matrix_short = Matrix4::from(quaternion); - - let matrix_long = Matrix3::from(quaternion); - let matrix_long = Matrix4::from(matrix_long); - - assert_ulps_eq!(matrix_short, matrix_long); - } - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/point.rs b/third_party/cargo/vendor/cgmath-0.17.0/tests/point.rs deleted file mode 100755 index 83fd168..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/point.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[macro_use] -extern crate approx; -extern crate cgmath; - -use cgmath::{Point1, Point2, Point3}; - -macro_rules! impl_test_mul { - ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // point * scalar ops - assert_eq!($v * $s, $PointN::new($($v.$field * $s),+)); - assert_eq!($s * $v, $PointN::new($($s * $v.$field),+)); - assert_eq!(&$v * $s, $v * $s); - assert_eq!($s * &$v, $s * $v); - // commutativity - assert_eq!($v * $s, $s * $v); - ) -} - -macro_rules! impl_test_div { - ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // point / scalar ops - assert_eq!($v / $s, $PointN::new($($v.$field / $s),+)); - assert_eq!($s / $v, $PointN::new($($s / $v.$field),+)); - assert_eq!(&$v / $s, $v / $s); - assert_eq!($s / &$v, $s / $v); - ) -} - -macro_rules! impl_test_rem { - ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // point % scalar ops - assert_eq!($v % $s, $PointN::new($($v.$field % $s),+)); - assert_eq!($s % $v, $PointN::new($($s % $v.$field),+)); - assert_eq!(&$v % $s, $v % $s); - assert_eq!($s % &$v, $s % $v); - ) -} - -#[test] -fn test_homogeneous() { - let p = Point3::new(1.0f64, 2.0f64, 3.0f64); - assert_ulps_eq!(&p, &Point3::from_homogeneous(p.to_homogeneous())); -} - -#[test] -fn test_mul() { - impl_test_mul!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); - impl_test_mul!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); -} - -#[test] -fn test_div() { - impl_test_div!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); - impl_test_div!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); -} - -#[test] -fn test_rem() { - impl_test_rem!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); - impl_test_rem!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); -} - -#[test] -fn test_cast() { - assert_ulps_eq!(Point1::new(0.9f64).cast().unwrap(), Point1::new(0.9f32)); - assert_ulps_eq!( - Point2::new(0.9f64, 1.5).cast().unwrap(), - Point2::new(0.9f32, 1.5) - ); - assert_ulps_eq!( - Point3::new(1.0f64, 2.4, -3.13).cast().unwrap(), - Point3::new(1.0f32, 2.4, -3.13) - ); -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/quaternion.rs b/third_party/cargo/vendor/cgmath-0.17.0/tests/quaternion.rs deleted file mode 100755 index f1ffd9f..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/quaternion.rs +++ /dev/null @@ -1,472 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[macro_use] -extern crate approx; -extern crate cgmath; - -macro_rules! impl_test_mul { - ($s:expr, $v:expr) => ( - // point * scalar ops - assert_eq!($v * $s, Quaternion::from_sv($v.s * $s, $v.v * $s)); - assert_eq!($s * $v, Quaternion::from_sv($s * $v.s, $s * $v.v)); - assert_eq!(&$v * $s, $v * $s); - assert_eq!($s * &$v, $s * $v); - // commutativity - assert_eq!($v * $s, $s * $v); - ) -} - -macro_rules! impl_test_div { - ($s:expr, $v:expr) => ( - // point / scalar ops - assert_eq!($v / $s, Quaternion::from_sv($v.s / $s, $v.v / $s)); - assert_eq!($s / $v, Quaternion::from_sv($s / $v.s, $s / $v.v)); - assert_eq!(&$v / $s, $v / $s); - assert_eq!($s / &$v, $s / $v); - ) -} - -mod operators { - use cgmath::*; - - #[test] - fn test_mul() { - impl_test_mul!( - 2.0f32, - Quaternion::from(Euler { - x: Rad(1f32), - y: Rad(1f32), - z: Rad(1f32), - }) - ); - } - - #[test] - fn test_div() { - impl_test_div!( - 2.0f32, - Quaternion::from(Euler { - x: Rad(1f32), - y: Rad(1f32), - z: Rad(1f32), - }) - ); - } - - #[test] - fn test_iter_sum() { - let q1 = Quaternion::from(Euler { - x: Rad(2f32), - y: Rad(1f32), - z: Rad(1f32), - }); - let q2 = Quaternion::from(Euler { - x: Rad(1f32), - y: Rad(2f32), - z: Rad(1f32), - }); - let q3 = Quaternion::from(Euler { - x: Rad(1f32), - y: Rad(1f32), - z: Rad(2f32), - }); - - assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().sum()); - assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().cloned().sum()); - } - - #[test] - fn test_iter_product() { - let q1 = Quaternion::from(Euler { - x: Rad(2f32), - y: Rad(1f32), - z: Rad(1f32), - }); - let q2 = Quaternion::from(Euler { - x: Rad(1f32), - y: Rad(2f32), - z: Rad(1f32), - }); - let q3 = Quaternion::from(Euler { - x: Rad(1f32), - y: Rad(1f32), - z: Rad(2f32), - }); - - assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().product()); - assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().cloned().product()); - } -} - -mod to_from_euler { - use std::f32; - - use cgmath::*; - - fn check_euler(rotation: Euler>) { - assert_relative_eq!( - Euler::from(Quaternion::from(rotation)), - rotation, - epsilon = 0.001 - ); - } - - const HPI: f32 = f32::consts::FRAC_PI_2; - - #[test] - fn test_zero() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(0f32), - z: Rad(0f32), - }); - } - #[test] - fn test_yaw_pos_1() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(1f32), - z: Rad(0f32), - }); - } - #[test] - fn test_yaw_neg_1() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(-1f32), - z: Rad(0f32), - }); - } - #[test] - fn test_pitch_pos_1() { - check_euler(Euler { - x: Rad(1f32), - y: Rad(0f32), - z: Rad(0f32), - }); - } - #[test] - fn test_pitch_neg_1() { - check_euler(Euler { - x: Rad(-1f32), - y: Rad(0f32), - z: Rad(0f32), - }); - } - #[test] - fn test_roll_pos_1() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(0f32), - z: Rad(1f32), - }); - } - #[test] - fn test_roll_neg_1() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(0f32), - z: Rad(-1f32), - }); - } - #[test] - fn test_pitch_yaw_roll_pos_1() { - check_euler(Euler { - x: Rad(1f32), - y: Rad(1f32), - z: Rad(1f32), - }); - } - #[test] - fn test_pitch_yaw_roll_neg_1() { - check_euler(Euler { - x: Rad(-1f32), - y: Rad(-1f32), - z: Rad(-1f32), - }); - } - #[test] - fn test_pitch_yaw_roll_pos_hp() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(HPI), - z: Rad(1f32), - }); - } - #[test] - fn test_pitch_yaw_roll_neg_hp() { - check_euler(Euler { - x: Rad(0f32), - y: Rad(-HPI), - z: Rad(1f32), - }); - } -} - -mod from { - mod matrix3 { - use cgmath::*; - - fn check_with_euler(x: Rad, y: Rad, z: Rad) { - let matrix3 = Matrix3::from(Euler { x: x, y: y, z: z }); - let quaternion = Quaternion::from(matrix3); - let quaternion_matrix3 = Matrix3::from(quaternion); - assert_ulps_eq!(matrix3, quaternion_matrix3); - } - - // triggers: trace >= S::zero() - #[test] - fn test_positive_trace() { - check_with_euler(Rad(0.0f32), Rad(0.0), Rad(0.0f32)); - } - - // triggers: (mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2]) - #[test] - fn test_xx_maximum() { - check_with_euler(Rad(2.0f32), Rad(1.0), Rad(-1.2f32)); - } - - // triggers: mat[1][1] > mat[2][2] - #[test] - fn test_yy_maximum() { - check_with_euler(Rad(2.0f32), Rad(1.0), Rad(3.0f32)); - } - - // base case - #[test] - fn test_zz_maximum() { - check_with_euler(Rad(1.0f32), Rad(1.0), Rad(3.0f32)); - } - } -} - -mod arc { - use cgmath::*; - - #[inline] - fn test(src: Vector3, dst: Vector3) { - let q = Quaternion::from_arc(src, dst, None); - let v = q.rotate_vector(src); - assert_ulps_eq!(v.normalize(), dst.normalize()); - } - - #[test] - fn test_same() { - let v = Vector3::unit_x(); - let q = Quaternion::from_arc(v, v, None); - assert_eq!(q, Quaternion::new(1.0, 0.0, 0.0, 0.0)); - } - - #[test] - fn test_opposite() { - let v = Vector3::unit_x(); - test(v, -v); - } - - #[test] - fn test_random() { - test(vec3(1.0, 2.0, 3.0), vec3(-4.0, 5.0, -6.0)); - } - - #[test] - fn test_ortho() { - let q: Quaternion = Quaternion::from_arc(Vector3::unit_x(), Vector3::unit_y(), None); - let q2 = Quaternion::from_axis_angle(Vector3::unit_z(), Rad::turn_div_4()); - assert_ulps_eq!(q, q2); - } -} - -mod rotate_from_euler { - use cgmath::*; - - #[test] - fn test_x() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Quaternion::from(Euler::new(Deg(90.0), Deg(0.0), Deg(0.0))); - assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); - - let rot = Quaternion::from(Euler::new(Deg(-90.0), Deg(0.0), Deg(0.0))); - assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); - } - - #[test] - fn test_y() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(90.0), Deg(0.0))); - assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); - - let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(-90.0), Deg(0.0))); - assert_ulps_eq!(vec3(-1.0, 0.0, 0.0), rot * vec); - } - - #[test] - fn test_z() { - let vec = vec3(1.0, 0.0, 0.0); - - let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(0.0), Deg(90.0))); - assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); - - let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(0.0), Deg(-90.0))); - assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); - } - - // tests that the Y rotation is done after the X - #[test] - fn test_x_then_y() { - let vec = vec3(0.0, 1.0, 0.0); - - let rot = Quaternion::from(Euler::new(Deg(90.0), Deg(90.0), Deg(0.0))); - assert_ulps_eq!(vec3(0.0f32, 0.0f32, 1.0f32), rot * vec); - } - - // tests that the Z rotation is done after the Y - #[test] - fn test_y_then_z() { - let vec = vec3(0.0f32, 0.0f32, 1.0f32); - - let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(90.0), Deg(90.0))); - assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); - } -} - -mod rotate_from_axis_angle { - use cgmath::*; - - #[test] - fn test_x() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Quaternion::from_angle_x(Deg(90.0)); - assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); - } - - #[test] - fn test_y() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Quaternion::from_angle_y(Deg(90.0)); - assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); - } - - #[test] - fn test_z() { - let vec = vec3(1.0, 0.0, 0.0); - - let rot = Quaternion::from_angle_z(Deg(90.0)); - assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); - } - - #[test] - fn test_xy() { - let vec = vec3(0.0, 0.0, 1.0); - - let rot = Quaternion::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), Deg(90.0)); - assert_ulps_eq!( - vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0), - rot * vec - ); - } - - #[test] - fn test_yz() { - let vec = vec3(1.0, 0.0, 0.0); - - let rot = Quaternion::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), Deg(-90.0)); - assert_ulps_eq!( - vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0), - rot * vec - ); - } - - #[test] - fn test_xz() { - let vec = vec3(0.0, 1.0, 0.0); - - let rot = Quaternion::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), Deg(90.0)); - assert_ulps_eq!( - vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), - rot * vec - ); - } -} - -mod rotate_between_vectors { - use cgmath::*; - - #[test] - fn test_around_z_0() { - let expected = Quaternion::new(1.0, 0.0, 0.0, 0.0); - - let a = vec3(12.0, 0.0, 0.0); - let b = vec3(1.0, 0.0, 0.0); - - assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); - } - - #[test] - fn test_around_z_90_cw() { - let expected = Quaternion::new(0.5_f32.sqrt(), 0.0, 0.0, 0.5_f32.sqrt()); - - let a = vec3(8.0, 0.0, 0.0); - let b = vec3(0.0, 9.0, 0.0); - - assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); - } - - #[test] - fn test_around_z_90_ccw() { - let expected = Quaternion::new(0.5_f32.sqrt(), 0.0, 0.0, -0.5_f32.sqrt()); - - let a = vec3(-26.0, 0.0, 0.0); - let b = vec3(0.0, 10.0, 0.0); - - assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); - } - - #[test] - fn test_around_z_180_cw() { - let expected = Quaternion::new(0.0, 0.0, 0.0, 1.0); - - let a = vec3(10.0, 0.0, 0.0); - let b = vec3(-5.0, 0.0, 0.0); - - assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); - } - - #[test] - fn test_around_z_180_ccw() { - let expected = Quaternion::new(0.0, 0.0, 0.0, -1.0); - - let a = vec3(-3.0, 0.0, 0.0); - let b = vec3(40.0, 0.0, 0.0); - - assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); - } -} - -mod cast { - use cgmath::*; - - #[test] - fn test_cast() { - assert_ulps_eq!( - Quaternion::new(0.9f64, 1.5, 2.4, 7.6).cast().unwrap(), - Quaternion::new(0.9f32, 1.5, 2.4, 7.6) - ); - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/rotation.rs b/third_party/cargo/vendor/cgmath-0.17.0/tests/rotation.rs deleted file mode 100755 index b661d31..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/rotation.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -extern crate cgmath; - -use cgmath::*; - -mod rotation { - use super::cgmath::*; - - pub fn a2>() -> R { - Rotation2::from_angle(Deg(30.0)) - } - - pub fn a3>() -> R { - let axis = Vector3::new(1.0, 1.0, 0.0).normalize(); - Rotation3::from_axis_angle(axis, Deg(30.0)) - } -} - -#[test] -fn test_invert_basis2() { - let a: Basis2<_> = rotation::a2(); - let a = a * a.invert(); - let a: &Matrix2<_> = a.as_ref(); - assert!(a.is_identity()); -} - -#[test] -fn test_invert_basis3() { - let a: Basis3<_> = rotation::a3(); - let a = a * a.invert(); - let a: &Matrix3<_> = a.as_ref(); - assert!(a.is_identity()); -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/transform.rs b/third_party/cargo/vendor/cgmath-0.17.0/tests/transform.rs deleted file mode 100755 index 13c9e5c..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/transform.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[macro_use] -extern crate approx; -extern crate cgmath; - -#[cfg(feature = "serde")] -extern crate serde_json; - -use cgmath::*; - -#[test] -fn test_invert() { - let v = Vector3::new(1.0f64, 2.0, 3.0); - let t = Decomposed { - scale: 1.5f64, - rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), - disp: Vector3::new(6.0f64, -7.0, 8.0), - }; - let ti = t.inverse_transform() - .expect("Expected successful inversion"); - let vt = t.transform_vector(v); - assert_ulps_eq!(&v, &ti.transform_vector(vt)); -} - -#[test] -fn test_inverse_vector() { - let v = Vector3::new(1.0f64, 2.0, 3.0); - let t = Decomposed { - scale: 1.5f64, - rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), - disp: Vector3::new(6.0f64, -7.0, 8.0), - }; - let vt = t.inverse_transform_vector(v) - .expect("Expected successful inversion"); - assert_ulps_eq!(v, t.transform_vector(vt)); -} - -#[test] -fn test_look_at() { - let eye = Point3::new(0.0f64, 0.0, -5.0); - let center = Point3::new(0.0f64, 0.0, 0.0); - let up = Vector3::new(1.0f64, 0.0, 0.0); - let t: Decomposed, Quaternion> = Transform::look_at(eye, center, up); - let point = Point3::new(1.0f64, 0.0, 0.0); - let view_point = Point3::new(0.0f64, 1.0, 5.0); - assert_ulps_eq!(&t.transform_point(point), &view_point); -} - -#[cfg(feature = "serde")] -#[test] -fn test_serialize() { - let t = Decomposed { - scale: 1.5f64, - rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), - disp: Vector3::new(6.0f64, -7.0, 8.0), - }; - - let serialized = serde_json::to_string(&t).unwrap(); - let deserialized: Decomposed, Quaternion> = - serde_json::from_str(&serialized).unwrap(); - - assert_ulps_eq!(&t, &deserialized); -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/vector.rs b/third_party/cargo/vendor/cgmath-0.17.0/tests/vector.rs deleted file mode 100755 index 325838a..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/vector.rs +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[macro_use] -extern crate approx; -extern crate cgmath; - -use cgmath::*; -use std::f64; -use std::iter; - -#[test] -fn test_constructor() { - assert_eq!(vec2(1f32, 2f32), Vector2::new(1f32, 2f32)); - assert_eq!(vec3(1f64, 2f64, 3f64), Vector3::new(1f64, 2f64, 3f64)); - assert_eq!( - vec4(1isize, 2isize, 3isize, 4isize), - Vector4::new(1isize, 2isize, 3isize, 4isize) - ); -} - -#[test] -fn test_from_value() { - assert_eq!( - Vector2::from_value(102isize), - Vector2::new(102isize, 102isize) - ); - assert_eq!( - Vector3::from_value(22isize), - Vector3::new(22isize, 22isize, 22isize) - ); - assert_eq!( - Vector4::from_value(76.5f64), - Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64) - ); -} - -macro_rules! impl_test_add { - ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // vector + vector ops - assert_eq!($v + $v, $VectorN::new($($v.$field + $v.$field),+)); - assert_eq!(&$v + &$v, $v + $v); - assert_eq!(&$v + $v, $v + $v); - assert_eq!($v + &$v, $v + $v); - ) -} - -macro_rules! impl_test_sub { - ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // vector - vector ops - assert_eq!($v - $v, $VectorN::new($($v.$field - $v.$field),+)); - assert_eq!(&$v - &$v, $v - $v); - assert_eq!(&$v - $v, $v - $v); - assert_eq!($v - &$v, $v - $v); - ) -} - -macro_rules! impl_test_mul { - ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // vector * scalar ops - assert_eq!($v * $s, $VectorN::new($($v.$field * $s),+)); - assert_eq!($s * $v, $VectorN::new($($s * $v.$field),+)); - assert_eq!(&$v * $s, $v * $s); - assert_eq!($s * &$v, $s * $v); - // commutativity - assert_eq!($v * $s, $s * $v); - ) -} - -macro_rules! impl_test_div { - ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // vector / scalar ops - assert_eq!($v / $s, $VectorN::new($($v.$field / $s),+)); - assert_eq!($s / $v, $VectorN::new($($s / $v.$field),+)); - assert_eq!(&$v / $s, $v / $s); - assert_eq!($s / &$v, $s / $v); - ) -} - -macro_rules! impl_test_rem { - ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( - // vector % scalar ops - assert_eq!($v % $s, $VectorN::new($($v.$field % $s),+)); - assert_eq!($s % $v, $VectorN::new($($s % $v.$field),+)); - assert_eq!(&$v % $s, $v % $s); - assert_eq!($s % &$v, $s % $v); - ) -} - -macro_rules! impl_test_iter_sum { - ($VectorN:ident { $($field:ident),+ }, $ty:ty, $s:expr, $v:expr) => ( - assert_eq!($VectorN::new($($v.$field * $s),+), - iter::repeat($v).take($s as usize).sum()); - ) -} - -#[test] -fn test_add() { - impl_test_add!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); - impl_test_add!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); - impl_test_add!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); -} - -#[test] -fn test_sub() { - impl_test_sub!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); - impl_test_sub!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); - impl_test_sub!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); -} - -#[test] -fn test_mul() { - impl_test_mul!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); - impl_test_mul!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); - impl_test_mul!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); -} - -#[test] -fn test_div() { - impl_test_div!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); - impl_test_div!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); - impl_test_div!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); -} - -#[test] -fn test_rem() { - impl_test_rem!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); - impl_test_rem!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); - impl_test_rem!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); -} - -#[test] -fn test_dot() { - assert_eq!(Vector2::new(1.0, 2.0).dot(Vector2::new(3.0, 4.0)), 11.0); - assert_eq!( - Vector3::new(1.0, 2.0, 3.0).dot(Vector3::new(4.0, 5.0, 6.0)), - 32.0 - ); - assert_eq!( - Vector4::new(1.0, 2.0, 3.0, 4.0).dot(Vector4::new(5.0, 6.0, 7.0, 8.0)), - 70.0 - ); -} - -#[test] -fn test_sum() { - assert_eq!(Vector2::new(1isize, 2isize).sum(), 3isize); - assert_eq!(Vector3::new(1isize, 2isize, 3isize).sum(), 6isize); - assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).sum(), 10isize); - - assert_eq!(Vector2::new(3.0f64, 4.0f64).sum(), 7.0f64); - assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).sum(), 15.0f64); - assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).sum(), 26.0f64); -} - -#[test] -fn test_iter_sum() { - impl_test_iter_sum!( - Vector4 { x, y, z, w }, - f32, - 2.0f32, - vec4(2.0f32, 4.0, 6.0, 8.0) - ); - impl_test_iter_sum!(Vector3 { x, y, z }, f32, 2.0f32, vec3(2.0f32, 4.0, 6.0)); - impl_test_iter_sum!(Vector2 { x, y }, f32, 2.0f32, vec2(2.0f32, 4.0)); - - impl_test_iter_sum!(Vector4 { x, y, z, w }, usize, 2usize, vec4(2usize, 4, 6, 8)); - impl_test_iter_sum!(Vector3 { x, y, z }, usize, 2usize, vec3(2usize, 4, 6)); - impl_test_iter_sum!(Vector2 { x, y }, usize, 2usize, vec2(2usize, 4)); -} - -#[test] -fn test_product() { - assert_eq!(Vector2::new(1isize, 2isize).product(), 2isize); - assert_eq!(Vector3::new(1isize, 2isize, 3isize).product(), 6isize); - assert_eq!( - Vector4::new(1isize, 2isize, 3isize, 4isize).product(), - 24isize - ); - - assert_eq!(Vector2::new(3.0f64, 4.0f64).product(), 12.0f64); - assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).product(), 120.0f64); - assert_eq!( - Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).product(), - 1680.0f64 - ); -} - -#[test] -fn test_cross() { - let a = Vector3::new(1isize, 2isize, 3isize); - let b = Vector3::new(4isize, 5isize, 6isize); - let r = Vector3::new(-3isize, 6isize, -3isize); - assert_eq!(a.cross(b), r); -} - -#[test] -fn test_is_perpendicular() { - assert!(Vector2::new(1.0f64, 0.0f64).is_perpendicular(Vector2::new(0.0f64, 1.0f64))); - assert!( - Vector3::new(0.0f64, 1.0f64, 0.0f64).is_perpendicular(Vector3::new(0.0f64, 0.0f64, 1.0f64)) - ); - assert!( - Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64).is_perpendicular(Vector4::new( - 0.0f64, - 0.0f64, - 0.0f64, - 1.0f64 - )) - ); -} - -#[cfg(test)] -mod test_magnitude { - use cgmath::*; - - #[test] - fn test_vector2() { - let (a, a_res) = (Vector2::new(3.0f64, 4.0f64), 5.0f64); // (3, 4, 5) Pythagorean triple - let (b, b_res) = (Vector2::new(5.0f64, 12.0f64), 13.0f64); // (5, 12, 13) Pythagorean triple - - assert_eq!(a.magnitude2(), a_res * a_res); - assert_eq!(b.magnitude2(), b_res * b_res); - - assert_eq!(a.magnitude(), a_res); - assert_eq!(b.magnitude(), b_res); - } - - #[test] - fn test_vector3() { - let (a, a_res) = (Vector3::new(2.0f64, 3.0f64, 6.0f64), 7.0f64); // (2, 3, 6, 7) Pythagorean quadruple - let (b, b_res) = (Vector3::new(1.0f64, 4.0f64, 8.0f64), 9.0f64); // (1, 4, 8, 9) Pythagorean quadruple - - assert_eq!(a.magnitude2(), a_res * a_res); - assert_eq!(b.magnitude2(), b_res * b_res); - - assert_eq!(a.magnitude(), a_res); - assert_eq!(b.magnitude(), b_res); - } - - #[test] - fn test_vector4() { - let (a, a_res) = (Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64), 11.0f64); // (1, 2, 4, 10, 11) Pythagorean quintuple - let (b, b_res) = (Vector4::new(1.0f64, 2.0f64, 8.0f64, 10.0f64), 13.0f64); // (1, 2, 8, 10, 13) Pythagorean quintuple - - assert_eq!(a.magnitude2(), a_res * a_res); - assert_eq!(b.magnitude2(), b_res * b_res); - - assert_eq!(a.magnitude(), a_res); - assert_eq!(b.magnitude(), b_res); - } -} - -#[test] -fn test_angle() { - assert_ulps_eq!( - Vector2::new(1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)), - &Rad(f64::consts::FRAC_PI_2) - ); - assert_ulps_eq!( - Vector2::new(10.0f64, 0.0f64).angle(Vector2::new(0.0f64, 5.0f64)), - &Rad(f64::consts::FRAC_PI_2) - ); - assert_ulps_eq!( - Vector2::new(-1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)), - &-Rad(f64::consts::FRAC_PI_2) - ); - - assert_ulps_eq!( - Vector3::new(1.0f64, 0.0f64, 1.0f64).angle(Vector3::new(1.0f64, 1.0f64, 0.0f64)), - &Rad(f64::consts::FRAC_PI_3) - ); - assert_ulps_eq!( - Vector3::new(10.0f64, 0.0f64, 10.0f64).angle(Vector3::new(5.0f64, 5.0f64, 0.0f64)), - &Rad(f64::consts::FRAC_PI_3) - ); - assert_ulps_eq!( - Vector3::new(-1.0f64, 0.0f64, -1.0f64).angle(Vector3::new(1.0f64, -1.0f64, 0.0f64)), - &Rad(2.0f64 * f64::consts::FRAC_PI_3) - ); - - assert_ulps_eq!( - Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64).angle(Vector4::new( - 0.0f64, - 1.0f64, - 0.0f64, - 1.0f64 - )), - &Rad(f64::consts::FRAC_PI_2) - ); - assert_ulps_eq!( - Vector4::new(10.0f64, 0.0f64, 10.0f64, 0.0f64).angle(Vector4::new( - 0.0f64, - 5.0f64, - 0.0f64, - 5.0f64 - )), - &Rad(f64::consts::FRAC_PI_2) - ); - assert_ulps_eq!( - Vector4::new(-1.0f64, 0.0f64, -1.0f64, 0.0f64).angle(Vector4::new( - 0.0f64, - 1.0f64, - 0.0f64, - 1.0f64 - )), - &Rad(f64::consts::FRAC_PI_2) - ); -} - -#[test] -fn test_normalize() { - // TODO: test normalize_to, normalize_sel.0, and normalize_self_to - assert_ulps_eq!( - Vector2::new(3.0f64, 4.0f64).normalize(), - &Vector2::new(3.0 / 5.0, 4.0 / 5.0) - ); - assert_ulps_eq!( - Vector3::new(2.0f64, 3.0f64, 6.0f64).normalize(), - &Vector3::new(2.0 / 7.0, 3.0 / 7.0, 6.0 / 7.0) - ); - assert_ulps_eq!( - Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64).normalize(), - &Vector4::new(1.0 / 11.0, 2.0 / 11.0, 4.0 / 11.0, 10.0 / 11.0) - ); -} - -#[test] -fn test_project_on() { - assert_ulps_eq!( - Vector2::new(-1.0f64, 5.0).project_on(Vector2::new(2.0, 4.0)), - &Vector2::new(9.0 / 5.0, 18.0 / 5.0) - ); - assert_ulps_eq!( - Vector3::new(5.0f64, 6.0, 7.0).project_on(Vector3::new(1.0, 1.0, 1.0)), - &Vector3::new(6.0, 6.0, 6.0) - ); - assert_ulps_eq!( - Vector4::new(0.0f64, -5.0, 5.0, 5.0).project_on(Vector4::new(0.0, 1.0, 0.0, 0.5)), - &Vector4::new(0.0, -2.0, 0.0, -1.0) - ); -} - -#[test] -fn test_cast() { - assert_ulps_eq!( - Vector2::new(0.9f64, 1.5).cast().unwrap(), - Vector2::new(0.9f32, 1.5) - ); - assert_ulps_eq!( - Vector3::new(1.0f64, 2.4, -3.13).cast().unwrap(), - Vector3::new(1.0f32, 2.4, -3.13) - ); - assert_ulps_eq!( - Vector4::new(13.5f64, -4.6, -8.3, 2.41).cast().unwrap(), - Vector4::new(13.5f32, -4.6, -8.3, 2.41) - ); -} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/.cargo-checksum.json b/third_party/cargo/vendor/cgmath-0.18.0/.cargo-checksum.json new file mode 100644 index 0000000..791a88c --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"c15937b4861c111ae924455ac56f6b4d3b272d2a456305db2337921b66d526bc","Cargo.toml":"c717a50be9b15417e71d40a75d834ad1ced5dd99b58aba8100132932ed4b8925","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"33df1f04235659699d1fe9fdc0a54b05a53d76ae928e432bab6ba841aa5ec4ff","benches/common/macros.rs":"a8e13d0eed7bf567d8359ceae9bbe3835ab74f823ab68e52a6c828793f112f7b","benches/construction.rs":"e5d77d5649f9a0a382652208a8071b3893041b52b0337797ec13998361da1d3d","benches/mat.rs":"c66f051d59c13999c3a2717287f98384eb5824277e0e3dadd347366cfb57c2d4","benches/quat.rs":"2be5545f004c69883d91e6f713211628a579538a1b014a034996bad22e445abe","benches/vec.rs":"53e4e8ba97aa02d0f0d4b1c95f9b9b9cdadbaa1a0448f0bd20d7b1fcdc000c8c","build.rs":"b60f3d324252ed4bdd1af256c4da636c7ea38648500a593d180d3d2c25ee0160","src/angle.rs":"ecd93d4b8a14af34f7019ca1a055d606824cbb4f64be20cf2c89b54f937b93ac","src/conv.rs":"186b801ec147054bdb7abb3d0ca1b78cc3b1ec7b9ca5d33a207c9e83b266d884","src/euler.rs":"d72618ff640df3aeae5bab8ee86ec2353731175d777b651a3cc99d10b9e348e9","src/lib.rs":"c0eda563f0d99684ac8e6267d1478f924890936f17a4e1a3d1067b32ecea0df8","src/macros.rs":"f7bb8fbe18b5ac54b711a6572deb13b7215e1ee77819478b625172d4620bee98","src/matrix.rs":"0e16d2266fc9b91dbd8e0ceb145c8a607d1b9209ed7a83d5ff9ad47a491673d4","src/num.rs":"6abf2fd71b3ddea02bbb4bffabcef90ca8f6d8a8291156876f591057483f70f4","src/point.rs":"e8af8081271f065466f160c055fbe9c1a29f0b8d984f27a9f3b6db3be53b6923","src/prelude.rs":"e02daa6ea97d656afb9828cff87cb9caf9567819df72ebcafcb6ed064ccbe616","src/projection.rs":"6658402316db26409110b066661335fd1a41d0728ea22533af2bc08dab371ec5","src/quaternion.rs":"87f78dbcbfd00ed177908bb7fe352e51e845097b7e91420a5b848eda4b33999d","src/quaternion_simd.rs":"4835d3f05540d8855e310594d2d1b40aca0f382626c0e00cb89b549e27210451","src/rotation.rs":"93996d530222ef67b52d3e695d8c0ad1e3c4886cf26450a9d46cbed2e9fb104d","src/structure.rs":"c21b2cbd0372c8c7653ab3b66140766f8ea94af4bf1d5035687e3a61e52628dd","src/transform.rs":"13d7697b04845d5a75cef798fd5ec6039b4599d19923f4faefd4e9048f3f45f1","src/vector.rs":"55b00baba047db1e689bf7e93e64267d9f479dbbaa69afdf57e595419e117011","src/vector_simd.rs":"db67ec5bfebffb198bf9f15c4731ef4e922d8bb7a14e21911d49f7253bda7aa2","tests/angle.rs":"d1e4b06bcd5e37fdb4ff201607c719eb3b116ac840766b24804e78bac39a3e5a","tests/matrix.rs":"087e12453fd08360cc4663678ab3a55cf23fb2a8be2eab8f6aa2f5a9cd6e00c1","tests/point.rs":"e3f614a679dc27c8fb4412f9428cb8e62aebcc84be2d72e40e9e9b76321334c8","tests/projection.rs":"f5156fd39109932726e1633ffcb12e4871a2bbb88469a8e45f74edb9f1b11f0c","tests/quaternion.rs":"2e7432ab000ed595d6bab85830a476e6a4da1dabc0cdfb7273ee2618cb10f32c","tests/rotation.rs":"3c3b8c25958d73ff839c0a54a3e972f506b176c0a90854e23d435d15f2af9484","tests/swizzle.rs":"4e6bd2b7beb70f57512f22f5bd3690a027ca196aef4b9f116c4e5d1a079d00c8","tests/transform.rs":"d533a7adc929e890ba591061eabc1406ddfdab87cdd552c01cdcf22153f2884e","tests/vector.rs":"ef595241a981935b4c589663189dc095a7ad4de91afaf6b7749662d659d8844b","tests/vector4f32.rs":"6410aaeb23091176b42e061c4755de4eee2e458aacb81979f1f3ba6b4ba110dc"},"package":"1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cgmath-0.18.0/BUILD.bazel b/third_party/cargo/vendor/cgmath-0.18.0/BUILD.bazel new file mode 100644 index 0000000..abe2ab8 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/BUILD.bazel @@ -0,0 +1,112 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Apache-2.0 from expression "Apache-2.0" +]) + +# Generated Targets +# buildifier: disable=load-on-top +load( + "@io_bazel_rules_rust//cargo:cargo_build_script.bzl", + "cargo_build_script", +) + +cargo_build_script( + name = "cgmath_build_script", + srcs = glob(["**/*.rs"]), + build_script_env = { + }, + crate_features = [ + ], + crate_root = "build.rs", + data = glob(["**"]), + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.18.0", + visibility = ["//visibility:private"], + deps = [ + ], +) + +# Unsupported target "construction" with type "bench" omitted + +# Unsupported target "mat" with type "bench" omitted + +# Unsupported target "quat" with type "bench" omitted + +# Unsupported target "vec" with type "bench" omitted + +rust_library( + name = "cgmath", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.18.0", + # buildifier: leave-alone + deps = [ + ":cgmath_build_script", + "//third_party/cargo/vendor/approx-0.4.0:approx", + "//third_party/cargo/vendor/num-traits-0.2.14:num_traits", + ], +) + +# Unsupported target "angle" with type "test" omitted + +# Unsupported target "matrix" with type "test" omitted + +# Unsupported target "point" with type "test" omitted + +# Unsupported target "projection" with type "test" omitted + +# Unsupported target "quaternion" with type "test" omitted + +# Unsupported target "rotation" with type "test" omitted + +# Unsupported target "swizzle" with type "test" omitted + +# Unsupported target "transform" with type "test" omitted + +# Unsupported target "vector" with type "test" omitted + +# Unsupported target "vector4f32" with type "test" omitted diff --git a/third_party/cargo/vendor/cgmath-0.18.0/CHANGELOG.md b/third_party/cargo/vendor/cgmath-0.18.0/CHANGELOG.md new file mode 100644 index 0000000..899a0f7 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/CHANGELOG.md @@ -0,0 +1,362 @@ +# Change Log + +All notable changes to this project will be documented in this file, following +the format defined at [keepachangelog.com](http://keepachangelog.com/). +This project adheres to [Semantic Versioning](http://semver.org/). + +## [Unreleased] + +### Changed + + - Refactored dependencies of experimental "specialization" feature into + default_fn! macro to reduce code duplication and complexity. Currently + only needed for non-functional SIMD feature. + - Refactored SIMD code into separate source files. See README.md for details. + - **Breaking**: Quaternion memory layout changed to `[x, y, z, w]`. The + `From` and `Into` impls for `[S; 4]` and `(S, S, S, S)` have been changed + accordingly. + + +### Added + + - Add `VectorN::zip` and `PointN::zip` + +## [v0.17.0] - 2019-01-17 + +### Added + + - Add signed `Angle` normalization + +### Changed + + - Move `lerp()` from `InnerSpace` to `VectorSpace` + - `const` constructors + +## [v0.16.1] - 2018-03-21 + +### Added + + - Implement `ElementWise` trait for point types + - Add `map` function to points and vectors + +### Changed + + - Remove `BaseNum` trait requirement for `PointN::new` functions + +## [v0.16.0] - 2018-01-03 + +### Added + +- Add `InnerSpace::project_on` +- Add `Array::len` +- Re-export `Bounded` and implement for vectors, points, and angles +- Add vector subtraction to `EuclideanSpace` +- Add swizzle functions behinde that `"swizzle"` feature +- Add `Matrix4::look_at_dir` + +### Changed + +- Return `Option` from cast functions + +## [v0.15.0] - 2017-07-30 + +### Added + +- Implement `mint` conversions behind a feature +- Add `Quaternion::cast` + +### Changed + +- Rename `use_simd` feature to `simd` +- Rename `eders` feature to `serde` + +### Fixed + +- Fix matrix inversions for small determinants + +## [v0.14.1] - 2017-05-02 + +### Fixed + +- Add a workaround for rust-lang/rust#41478, and in the process cleaned up + some type projections for angles + +## [v0.14.0] - 2017-04-26 + +## Changed + +- Constrain `VectorSpace`, `Rotation`, and `Angle` by `iter::Sum` +- Constrain `SquareMatrix` by `iter::Product` + +## [v0.13.1] - 2017-04-22 + +### Changed + +- Update `serde` and `serde_derive` to version `1.0`. + +## [v0.13.0] - 2017-04-14 + +### Added + +- Add optional `use_simd` feature to improve the performance of `Vector4`, + `Matrix4` and `Quaternion`. According to @DaseinPhaos in #394, under + the given benchmark certain operations were able to become up to 60% faster. +- Add component wise casting for the matrix and point types + +### Changed + +- Update `serde` to version `0.9`, and use `serde_derive` instead of `serde_macros`. + +## [v0.12.0] - 2016-09-14 + +### Changed + +- Use [approx](https://github.com/brendanzab/approx/) for approximate equality + comparisons +- Remove `#[repr(packed)]` from all structs where it was specified +- Update serde to 0.8 + +## [v0.11.0] - 2016-08-17 + +### Added + +- `Quaternion::from_arc` + +### Changed + +- Change the angle types to be tuple structs +- Make from-angle constructors take generic `Into>` values +- Fix `Decomposed::concat` implementation + +## [v0.10.0] - 2016-05-11 + +### Added + +- A `MetricSpace` trait for types that have a distance between elements. +- `EuclideanSpace::{midpoint, centroid}` functions with default + implementations. +- `Vector1` and `Point1` structs. +- Serde support behind the `eders` feature flag. +- An `ApproxEq` implementation for `Decomposed`. + +### Changed + +- Depend on the `num-traits` crate rather than `num`, seeing as we only use the + traits in `num`. `num_traits` has also been re-exported so that you can more + easily use these in your project. +- Use an `Euler` type for euler angle conversions. +- Constrain `InnerSpace` by `MetricSpace`. +- Constrain `Rotation` by `One` +- Implement `Transform` and `Transform3` for `Matrix4`. +- Implement `Transform`, `Transform2`, and `Transform3` for `Matrix4`. +- Fix `Euler`-`Quaternion` and `Quaternion`-`Euler` conversions. The axes are + now correct, and the angles are applied in _x_-_y_-_z_ order. The conversion now + matches the conversion from axis angle. +- Fix `Euler`-`{Matrix3, Matrix4}` conversions. + +## Removed + +- `Rotation::transform_as_point` +- `AffineMatrix3` +- `Rotation::invert_self` +- `Matrix::invert_self` + +## [v0.9.1] - 2016-04-20 + +### Changed + +- Fix angle assignment operators so that they actually mutate `self`. + +## [v0.9.0] - 2016-04-19 + +### Changed + +- Assignment operators implementations have been stabilised, to coincide with + their [stabilisation in Rust 1.8](http://blog.rust-lang.org/2016/04/14/Rust-1.8.html). +- Renames `Vector` trait to `VectorSpace`. +- Renames `EuclideanVector` to `InnerSpace`. +- Renames `Point` to `EuclideanSpace`, and `Point::Vector` to `EuclideanSpace::Diff`. +- `Quaternion`s now implement `VectorSpace` and `InnerSpace` for the functions + they share. +- The `Matrix` trait is now constraint by `VectorSpace`, with `Matrix::Element` + removed in favor of `VectorSpace::Scalar`. + +## [v0.8.0] - 2016-04-06 + +### Added + +- Implements `fmt::Debug` for `Basis2`, `Basis3`, and `AffineMatrix3` +- A `prelude` module for easy importing of common traits. +- Constrained conversion functions for assisting in situations where type + inference is difficult. +- An `ElementWise` trait for non-mathematical element-wise operations. +- A default implementation for `EuclideanVector::angle`. + +### Changed + +- Improves the `fmt::Debug` impls for `Vector`, `Matrix`, `Point`, `Decomposed`, + `Quaternion` and `Angle` to make them easier to derive, and have clearer + formatting. +- Marks vectors, points, matrices, and angles as `#[repr(C, packed)]`. +- Renames the `Vector::{length, length2}` functions to `Vector::{magnitude, magnitude2}`. +- Move `Angle::new` to be directly implemented on the `Rad` and `Deg` types. +- Move `Vector::dot` to `EuclideanVector` trait. +- Move `Vector::from_value` to `Array` trait. + +### Removed + +- The non-mathematical operator trait implementations have been removed from + the `Vector` trait, in favor of the `ElementWise` trait. +- `Angle::equiv`. +- Remove `neg_self` method on vectors and matrices. + +## [v0.7.0] - 2015-12-23 + +### Added +- Add missing by-ref and by-val permutations of `Vector`, `Matrix`, `Point`, + `Quaternion` and `Angle` operators. +- Ease lifetime constraints by removing `'static` from some scalar type + parameters. +- Weaken type constraints on `perspective` function to take an `Into>`. +- Add `Angle::new` for constructing angles from a unitless scalar. +- Implement assignment operators for nightly builds, enabled by the `"unstable"` + feature. + +### Changed +- `Vector`, `Matrix`, `Point`, and `Angle` are now constrained to require + specific operators to be overloaded. This means that generic code can now use + operators, instead of the operator methods. +- Take a `Rad` for `ProjectionFov::fovy`, rather than arbitrary `Angle`s. This + simplifies the signature of `PerspectiveFov` from `PerspectiveFov` to + `PerspectiveFov`. +- The following trait constraints were removed from `Angle`: `Debug`, + `ScalarConv`, `Into>`, `Into>`. +- `Angle` no longer requires `One`, and the implementations have been removed + from `Deg` and `Rad`. This is because angles do not close over multiplication, + and therefore cannot have a multiplicative identity. If we were truly accurate, + `Angle * Angle` would return an `Angle^2` (not supported by the current api). +- Make remainder operators on `Angle`s make sense from the perspective of + dimensional analysis. +- Moved free trigonometric functions onto `Angle`. + +### Removed +- Remove redundant `Point::{min, max}` methods - these are now covered by the + `Array::{min, max}` methods that were introduced in 0.5.0. +- Removed `ToComponents`, `ToComponents2`, and `ToComponents3`. If you were + relying on `ToComponents::decompose`, you can produce the same effect by + accessing the fields on `Decomposed` directly. To create the scale vector, + use: `Vector::from_value(transform.scale)`. +- Removed `CompositeTransform`, `CompositeTransform2`, and `CompositeTransform3`. +- Remove `Vector::one`. Vectors don't really have a multiplicative identity. + If you really want a `one` vector, you can do something like: + `Vector::from_value(1.0)`. +- Remove operator methods from `Vector`, `Matrix`, `Point`, and `Angle` traits + in favor of operator overloading. +- Remove `*_self` methods from `Vector`, `Matrix`, `Point`, and `Angle`. The + operator methods can be used via the unstable assignment operators. +- Remove `#[derive(Hash)]` from `Deg` and `Rad`. This could never really be used + these types, because they expect to be given a `BaseFloat` under normal + circumstances. + +## [v0.6.0] - 2015-12-12 + +### Added +- This CHANGELOG for keeping track of notable changes. +- `Matrix4::{from_scale, from_nonuniform_scale}` for easily constructing + homogeneous scale matrices. + +### Changed +- Renamed `SquareMatrix::one` to `SquareMatrix::identity`. `identity` is easier + to search for, + and the more common name for the multiplicative identity for matrices. +- Matrix impls have now been constrained to `S: BaseFloat`. + +## [v0.5.0] - 2015-11-20 + +### Changed +- Take many point and vector parameters by value. +- Take point and vector operator overloads by value. +- Divide `Matrix` trait into `Matrix` and `SquareMatrix`, opening the door for + non-square matrices in the future. +- Make many trait type parameters associated types. +- Move element-wise methods from `Vector` and `Point` onto the `Array1` trait, + and rename it to `Array`. +- Make pointer access methods on `Array` match the naming scheme of those in the + standard library. + +### Removed +- Removed collision types: `Ray`, `Plane`, `Frustum`, `Aabb2`, `Aabb3` `Obb2`, + `Obb3` `Sphere`, `Cylinder`. These can now be found at + [csherratt/collision-rs](https://github.com/csherratt/collision-rs). +- Remove `Array2` trait, moving methods onto the `Matrix` trait. + +## [v0.4.0] - 2015-10-25 + +## [v0.3.1] - 2015-09-20 + +## [v0.3.0] - 2015-09-20 + +## [v0.2.0] - 2015-05-11 + +## [v0.1.6] - 2015-05-10 + +## [v0.1.5] - 2015-04-25 + +## [v0.1.4] - 2015-04-24 + +## [v0.1.3] - 2015-04-06 + +## [v0.1.2] - 2015-04-01 + +## [v0.1.1] - 2015-03-25 + +## [v0.1.0] - 2015-03-15 + +## [v0.0.8] - 2015-03-09 + +## [v0.0.7] - 2015-03-01 + +## [v0.0.6] - 2015-02-21 + +## [v0.0.5] - 2015-02-16 + +## [v0.0.4] - 2015-02-11 + +## [v0.0.3] - 2015-02-08 + +## v0.0.1 - 2014-06-24 + +[Unreleased]: https://github.com/brendanzab/cgmath/compare/v0.16.1...HEAD +[v0.16.1]: https://github.com/brendanzab/cgmath/compare/v0.16.0...v0.16.1 +[v0.16.0]: https://github.com/brendanzab/cgmath/compare/v0.15.0...v0.16.0 +[v0.15.0]: https://github.com/brendanzab/cgmath/compare/v0.14.1...v0.15.0 +[v0.14.1]: https://github.com/brendanzab/cgmath/compare/v0.14.0...v0.14.1 +[v0.14.0]: https://github.com/brendanzab/cgmath/compare/v0.13.1...v0.14.0 +[v0.13.1]: https://github.com/brendanzab/cgmath/compare/v0.13.0...v0.13.1 +[v0.12.0]: https://github.com/brendanzab/cgmath/compare/v0.12.0...v0.13.0 +[v0.12.0]: https://github.com/brendanzab/cgmath/compare/v0.11.0...v0.12.0 +[v0.11.0]: https://github.com/brendanzab/cgmath/compare/v0.10.0...v0.11.0 +[v0.10.0]: https://github.com/brendanzab/cgmath/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/brendanzab/cgmath/compare/v0.9.0...v0.9.1 +[v0.9.0]: https://github.com/brendanzab/cgmath/compare/v0.8.0...v0.9.0 +[v0.8.0]: https://github.com/brendanzab/cgmath/compare/v0.7.0...v0.8.0 +[v0.7.0]: https://github.com/brendanzab/cgmath/compare/v0.6.0...v0.7.0 +[v0.6.0]: https://github.com/brendanzab/cgmath/compare/v0.5.0...v0.6.0 +[v0.5.0]: https://github.com/brendanzab/cgmath/compare/v0.4.0...v0.5.0 +[v0.4.0]: https://github.com/brendanzab/cgmath/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/brendanzab/cgmath/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/brendanzab/cgmath/compare/v0.2.0...v0.3.0 +[v0.2.0]: https://github.com/brendanzab/cgmath/compare/v0.1.6...v0.2.0 +[v0.1.6]: https://github.com/brendanzab/cgmath/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/brendanzab/cgmath/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/brendanzab/cgmath/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/brendanzab/cgmath/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/brendanzab/cgmath/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/brendanzab/cgmath/compare/v0.1.0...v0.1.1 +[v0.1.0]: https://github.com/brendanzab/cgmath/compare/v0.0.8...v0.1.0 +[v0.0.8]: https://github.com/brendanzab/cgmath/compare/v0.0.7...v0.0.8 +[v0.0.7]: https://github.com/brendanzab/cgmath/compare/v0.0.6...v0.0.7 +[v0.0.6]: https://github.com/brendanzab/cgmath/compare/v0.0.5...v0.0.6 +[v0.0.5]: https://github.com/brendanzab/cgmath/compare/v0.0.4...v0.0.5 +[v0.0.4]: https://github.com/brendanzab/cgmath/compare/v0.0.3...v0.0.4 +[v0.0.3]: https://github.com/brendanzab/cgmath/compare/v0.0.1...v0.0.3 diff --git a/third_party/cargo/vendor/cgmath-0.18.0/Cargo.toml b/third_party/cargo/vendor/cgmath-0.18.0/Cargo.toml new file mode 100644 index 0000000..2c1c271 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/Cargo.toml @@ -0,0 +1,51 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cgmath" +version = "0.18.0" +authors = ["Rust game-developers"] +description = "A linear algebra and mathematics library for computer graphics." +homepage = "https://github.com/rustgd/cgmath" +documentation = "https://docs.rs/cgmath" +readme = "README.md" +keywords = ["gamedev", "math", "matrix", "vector", "quaternion"] +license = "Apache-2.0" +repository = "https://github.com/rustgd/cgmath" + +[lib] +name = "cgmath" +[dependencies.approx] +version = "0.4" + +[dependencies.mint] +version = "0.5" +optional = true + +[dependencies.num-traits] +version = "0.2" + +[dependencies.rand] +version = "0.8" +features = ["small_rng"] +optional = true + +[dependencies.serde] +version = "1.0" +features = ["serde_derive"] +optional = true +[dev-dependencies.serde_json] +version = "1.0" + +[features] +swizzle = [] +unstable = [] diff --git a/third_party/cargo/vendor/cgmath-0.17.0/LICENSE b/third_party/cargo/vendor/cgmath-0.18.0/LICENSE old mode 100755 new mode 100644 similarity index 100% rename from third_party/cargo/vendor/cgmath-0.17.0/LICENSE rename to third_party/cargo/vendor/cgmath-0.18.0/LICENSE diff --git a/third_party/cargo/vendor/cgmath-0.18.0/README.md b/third_party/cargo/vendor/cgmath-0.18.0/README.md new file mode 100644 index 0000000..d247a7f --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/README.md @@ -0,0 +1,82 @@ +# cgmath-rs + +[![Build Status](https://github.com/rustgd/cgmath/workflows/tests/badge.svg)](https://github.com/rustgd/cgmath/actions) +[![Documentation](https://docs.rs/cgmath/badge.svg)](https://docs.rs/cgmath) +[![Version](https://img.shields.io/crates/v/cgmath.svg)](https://crates.io/crates/cgmath) +[![License](https://img.shields.io/crates/l/cgmath.svg)](https://github.com/rustgd/cgmath/blob/master/LICENSE) +[![Downloads](https://img.shields.io/crates/d/cgmath.svg)](https://crates.io/crates/cgmath) +[![Gitter](https://badges.gitter.im/brendanzab/cgmath.svg)](https://gitter.im/brendanzab/cgmath) + +A linear algebra and mathematics library for computer graphics. + +The library provides: + +- vectors: `Vector2`, `Vector3`, `Vector4` +- square matrices: `Matrix2`, `Matrix3`, `Matrix4` +- a quaternion type: `Quaternion` +- rotation matrices: `Basis2`, `Basis3` +- angle units: `Rad`, `Deg` +- points: `Point2`, `Point3` +- perspective projections: `Perspective`, `PerspectiveFov`, `Ortho` +- spatial transformations: `AffineMatrix3`, `Transform3` + +Not all of the functionality has been implemented yet, and the existing code +is not fully covered by the testsuite. If you encounter any mistakes or +omissions please let me know by posting an issue, or even better: send me a +pull request with a fix. + +## Conventions + +cgmath interprets its vectors as column matrices (also known as "column +vectors"), meaning when transforming a vector with a matrix, the matrix goes +on the left. This is reflected in the fact that cgmath implements the +multiplication operator for Matrix * Vector, but not Vector * Matrix. + +## Features + +### Swizzling +This library offers an optional feature called +["swizzling"](https://en.wikipedia.org/wiki/Swizzling_(computer_graphics)) +widely familiar to GPU programmers. To enable swizzle operators, pass the +`--features="swizzle"` option to cargo. Enabling this feature will increase +the size of the cgmath library by approximately 0.6MB. This isn't an +issue if the library is linked in the "normal" way by adding cgmath as a +dependency in Cargo.toml, which will link cgmath statically so all unused +swizzle operators will be optimized away by the compiler in release mode. + +#### Example +If we have +```rust +let v = Vector3::new(1.0, 2.0, 3.0); +``` +then `v.xyxz()` produces a +```rust +Vector4 { x: 1.0, y: 2.0, z: 1.0, w: 3.0 } +``` +and `v.zy()` produces a +```rust +Vector2 { x: 3.0, y: 2.0 } +``` +### SIMD optimizations + +The current SIMD support depends on the deprecated "simd" package as well +as the unstable "specialization" feature. To build this code, a pre-1.33 nightly +build of Rust is required, e.g. 2019-01-01-nightly. Though the code is not +useful in its present form, it has some worth preserving as starting point +for a future migration (see https://github.com/rustgd/cgmath/issues/490). + +## Limitations + +cgmath is _not_ an n-dimensional library and is aimed at computer graphics +applications rather than general linear algebra. It only offers the 2, 3, and +4 dimensional structures that are more than enough for most computer graphics +applications. This design decision was made in order to simplify the +implementation (Rust cannot parameterize over constants at compile time), and to +make dimension-specific optimisations easier in the future. + +## Contributing + +Pull requests are most welcome, especially in the realm of performance +enhancements and fixing any mistakes I may have made along the way. Unit tests +and benchmarks are also required, so help on that front would be most +appreciated. diff --git a/third_party/cargo/vendor/cgmath-0.18.0/benches/common/macros.rs b/third_party/cargo/vendor/cgmath-0.18.0/benches/common/macros.rs new file mode 100644 index 0000000..f857b58 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/benches/common/macros.rs @@ -0,0 +1,78 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +macro_rules! bench_binop { + ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { + #[bench] + fn $name(bh: &mut Bencher) { + const LEN: usize = 1 << 13; + + let mut rng = SmallRng::from_entropy(); + + let elems1: Vec<$t1> = (0..LEN).map(|_| rng.gen::<$t1>()).collect(); + let elems2: Vec<$t2> = (0..LEN).map(|_| rng.gen::<$t2>()).collect(); + let mut i = 0; + + bh.iter(|| { + i = (i + 1) & (LEN - 1); + + unsafe { test::black_box(elems1.get_unchecked(i).$binop(*elems2.get_unchecked(i))) } + }) + } + }; +} + +macro_rules! bench_unop { + ($name: ident, $t: ty, $unop: ident) => { + #[bench] + fn $name(bh: &mut Bencher) { + const LEN: usize = 1 << 13; + + let mut rng = SmallRng::from_entropy(); + + let mut elems: Vec<$t> = (0..LEN).map(|_| rng.gen::<$t>()).collect(); + let mut i = 0; + + bh.iter(|| { + i = (i + 1) & (LEN - 1); + + unsafe { test::black_box(elems.get_unchecked_mut(i).$unop()) } + }) + } + }; +} + +macro_rules! bench_construction { + ($name: ident, $t: ty, $constructor: path [ $($args: ident: $types: ty),+ ]) => { + #[bench] + fn $name(bh: &mut Bencher) { + const LEN: usize = 1 << 13; + + let mut rng = SmallRng::from_entropy(); + + $(let $args: Vec<$types> = (0..LEN).map(|_| rng.gen::<$types>()).collect();)* + let mut i = 0; + + bh.iter(|| { + i = (i + 1) & (LEN - 1); + + unsafe { + let res: $t = $constructor($(*$args.get_unchecked(i),)*); + test::black_box(res) + } + }) + } + }; +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/benches/construction.rs b/third_party/cargo/vendor/cgmath-0.18.0/benches/construction.rs old mode 100755 new mode 100644 similarity index 92% rename from third_party/cargo/vendor/cgmath-0.17.0/benches/construction.rs rename to third_party/cargo/vendor/cgmath-0.18.0/benches/construction.rs index 97244e8..e0a5062 --- a/third_party/cargo/vendor/cgmath-0.17.0/benches/construction.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/benches/construction.rs @@ -20,18 +20,19 @@ extern crate cgmath; extern crate rand; extern crate test; -use rand::{IsaacRng, Rng, FromEntropy}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; use test::Bencher; + use cgmath::*; #[path = "common/macros.rs"] #[macro_use] mod macros; -fn bench_from_axis_angle>(bh: &mut Bencher) { +fn bench_from_axis_angle>(bh: &mut Bencher) { const LEN: usize = 1 << 13; - let mut rng = IsaacRng::from_entropy(); + let mut rng = SmallRng::from_entropy(); let axis: Vec<_> = (0..LEN).map(|_| rng.gen::>()).collect(); let angle: Vec<_> = (0..LEN).map(|_| rng.gen::>()).collect(); diff --git a/third_party/cargo/vendor/cgmath-0.17.0/benches/mat.rs b/third_party/cargo/vendor/cgmath-0.18.0/benches/mat.rs old mode 100755 new mode 100644 similarity index 98% rename from third_party/cargo/vendor/cgmath-0.17.0/benches/mat.rs rename to third_party/cargo/vendor/cgmath-0.18.0/benches/mat.rs index f6fbf6e..c8130c6 --- a/third_party/cargo/vendor/cgmath-0.17.0/benches/mat.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/benches/mat.rs @@ -20,7 +20,7 @@ extern crate cgmath; extern crate rand; extern crate test; -use rand::{IsaacRng, Rng, FromEntropy}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; use std::ops::*; use test::Bencher; diff --git a/third_party/cargo/vendor/cgmath-0.17.0/benches/quat.rs b/third_party/cargo/vendor/cgmath-0.18.0/benches/quat.rs old mode 100755 new mode 100644 similarity index 95% rename from third_party/cargo/vendor/cgmath-0.17.0/benches/quat.rs rename to third_party/cargo/vendor/cgmath-0.18.0/benches/quat.rs index 0176216..31f9131 --- a/third_party/cargo/vendor/cgmath-0.17.0/benches/quat.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/benches/quat.rs @@ -14,12 +14,13 @@ // limitations under the License. #![feature(test)] +#![allow(unused_macros)] extern crate cgmath; extern crate rand; extern crate test; -use rand::{IsaacRng, Rng, FromEntropy}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; use std::ops::*; use test::Bencher; diff --git a/third_party/cargo/vendor/cgmath-0.18.0/benches/vec.rs b/third_party/cargo/vendor/cgmath-0.18.0/benches/vec.rs new file mode 100644 index 0000000..7b197af --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/benches/vec.rs @@ -0,0 +1,65 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![feature(test)] +#![allow(unused_macros)] + +extern crate cgmath; +extern crate rand; +extern crate test; + +use rand::{rngs::SmallRng, Rng, SeedableRng}; +use std::ops::*; +use test::Bencher; + +use cgmath::*; + +#[path = "common/macros.rs"] +#[macro_use] +mod macros; + +bench_binop!(_bench_vector2_add_v, Vector2, Vector2, add); +bench_binop!(_bench_vector3_add_v, Vector3, Vector3, add); +bench_binop!(_bench_vector4_add_v, Vector4, Vector4, add); + +bench_binop!(_bench_vector2_sub_v, Vector2, Vector2, sub); +bench_binop!(_bench_vector3_sub_v, Vector3, Vector3, sub); +bench_binop!(_bench_vector4_sub_v, Vector4, Vector4, sub); + +bench_binop!(_bench_vector2_mul_s, Vector2, f32, mul); +bench_binop!(_bench_vector3_mul_s, Vector3, f32, mul); +bench_binop!(_bench_vector4_mul_s, Vector4, f32, mul); + +bench_binop!(_bench_vector2_div_s, Vector2, f32, div); +bench_binop!(_bench_vector3_div_s, Vector3, f32, div); +bench_binop!(_bench_vector4_div_s, Vector4, f32, div); + +bench_binop!(_bench_vector2_rem_s, Vector2, f32, rem); +bench_binop!(_bench_vector3_rem_s, Vector3, f32, rem); +bench_binop!(_bench_vector4_rem_s, Vector4, f32, rem); + +bench_binop!(_bench_vector2_dot, Vector2, Vector2, dot); +bench_binop!(_bench_vector3_dot, Vector3, Vector3, dot); +bench_binop!(_bench_vector4_dot, Vector4, Vector4, dot); + +bench_binop!(_bench_vector3_cross, Vector3, Vector3, cross); + +bench_unop!(_bench_vector2_magnitude, Vector2, magnitude); +bench_unop!(_bench_vector3_magnitude, Vector3, magnitude); +bench_unop!(_bench_vector4_magnitude, Vector4, magnitude); + +bench_unop!(_bench_vector2_normalize, Vector2, normalize); +bench_unop!(_bench_vector3_normalize, Vector3, normalize); +bench_unop!(_bench_vector4_normalize, Vector4, normalize); diff --git a/third_party/cargo/vendor/cgmath-0.18.0/build.rs b/third_party/cargo/vendor/cgmath-0.18.0/build.rs new file mode 100644 index 0000000..e2cb378 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/build.rs @@ -0,0 +1,101 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::string::String; + +/// Generate the name of the swizzle function and what it returns. +/// NOTE: This function assumes that variables are in ASCII format +#[cfg(feature = "swizzle")] +fn gen_swizzle_nth<'a>(variables: &'a str, mut i: usize, upto: usize) -> Option<(String, String)> { + debug_assert!(i > 0); // zeroth permutation is empty + let mut swizzle_impl = String::new(); + let mut swizzle = String::new(); + let n = variables.len() + 1; + for _ in 0..upto { + if i == 0 { + break; + } + if i % n == 0 { + return None; + } + let c = variables.as_bytes()[i % n - 1] as char; + swizzle.push(c); + swizzle_impl.push_str(&format!("self.{}, ", c)); + i = i / n; + } + Some((swizzle, swizzle_impl)) +} + +/// A function that generates swizzle functions as a string. +/// `variables`: swizzle variables (e.g. "xyz") +/// `upto`: largest output vector size (e.g. for `variables = "xy"` and `upto = 4`, `xyxy()` is a +/// valid swizzle operator. +/// NOTE: This function assumes that variables are in ASCII format +#[cfg(feature = "swizzle")] +fn gen_swizzle_functions(variables: &'static str, upto: usize) -> String { + let mut result = String::new(); + let nn = (variables.len() + 1).pow(upto as u32); + for i in 1..nn { + if let Some((swizzle_name, swizzle_impl)) = gen_swizzle_nth(variables, i, upto) { + let dim = format!("{}", swizzle_name.len()); + result.push_str(&format!( + " + /// Swizzle operator that creates a new type with dimension {2} from variables `{0}`. + #[inline] pub fn {0}(&self) -> $vector_type{2}<$S> {{ $vector_type{2}::new({1}) }}\n", + swizzle_name, swizzle_impl, dim + )); + } + } + result +} + +#[cfg(not(feature = "swizzle"))] +fn gen_swizzle_functions(_: &'static str, _: usize) -> String { + String::new() +} + +/// This script generates the macro for building swizzle operators for multidimensional +/// vectors and points. This macro is included in macros.rs +fn main() { + // save the file to output directory + let out_dir = env::var("OUT_DIR").unwrap(); + let swizzle_file_path = Path::new(&out_dir).join("swizzle_operator_macro.rs"); + + // This is the string representing the generated macro + let data = format!( +"/// Generate glm/glsl style swizzle operators +macro_rules! impl_swizzle_functions {{ + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $S:ident, x) => {{ +{x3} + }}; + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $S:ident, xy) => {{ +{xy3} + }}; + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $S:ident, xyz) => {{ +{xyz3} + }}; + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, x) => {{ +{x4} + }}; + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, xy) => {{ +{xy4} + }}; + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, xyz) => {{ +{xyz4} + }}; + ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, xyzw) => {{ +{xyzw4} + }}; +}}", x3 = gen_swizzle_functions("x", 3), + xy3 = gen_swizzle_functions("xy", 3), + xyz3 = gen_swizzle_functions("xyz", 3), + x4 = gen_swizzle_functions("x", 4), + xy4 = gen_swizzle_functions("xy", 4), + xyz4 = gen_swizzle_functions("xyz", 4), + xyzw4 = gen_swizzle_functions("xyzw", 4)); + let mut f = File::create(swizzle_file_path) + .expect("Unable to create file that defines the swizzle operator macro."); + f.write_all(data.as_bytes()) + .expect("Unable to write swizzle operator macro."); +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/angle.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/angle.rs old mode 100755 new mode 100644 similarity index 97% rename from third_party/cargo/vendor/cgmath-0.17.0/src/angle.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/angle.rs index f932914..9f08422 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/angle.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/angle.rs @@ -15,15 +15,17 @@ //! Angle units for type-safe, self-documenting code. -use std::fmt; use std::f64; +use std::fmt; use std::iter; use std::ops::*; -use rand::Rng; -use rand::distributions::{Distribution, Standard}; -use rand::distributions::uniform::SampleUniform; use num_traits::{cast, Bounded}; +#[cfg(feature = "rand")] +use rand::{ + distributions::{uniform::SampleUniform, Distribution, Standard}, + Rng, +}; use structure::*; @@ -209,12 +211,13 @@ macro_rules! impl_angle { } } + #[cfg(feature = "rand")] impl Distribution<$Angle> for Standard where Standard: Distribution, S: BaseFloat + SampleUniform { #[inline] fn sample(&self, rng: &mut R) -> $Angle { - $Angle(rng.gen_range(cast::<_, S>(-$hi).unwrap(), cast::<_, S>($hi).unwrap())) + $Angle(rng.gen_range(cast::<_, S>(-$hi).unwrap() .. cast::<_, S>($hi).unwrap())) } } diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/conv.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/conv.rs old mode 100755 new mode 100644 similarity index 89% rename from third_party/cargo/vendor/cgmath-0.17.0/src/conv.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/conv.rs index 833ebef..a6abd42 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/conv.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/conv.rs @@ -4,7 +4,8 @@ //! For example, when declaring `glium` uniforms, we need to convert to fixed //! length arrays. We can use the `Into` trait directly, but it is rather ugly! //! -//! ```rust +//! --- Doc-test disabled because glium causes problems with nightly-2019-01-01 needed for "simd" +//! ` ` `rust //! #[macro_use] //! extern crate glium; //! extern crate cgmath; @@ -22,11 +23,12 @@ //! // Yuck!! (ノಥ益ಥ)ノ ┻━┻ //! }; //! # } -//! ``` +//! ` ` ` //! //! Instead, we can use the conversion functions from the `conv` module: //! -//! ```rust +//! --- Doc-test disabled because glium causes problems nightly-2019-01-01 needed for "simd" +//! ` ` `rust //! #[macro_use] //! extern crate glium; //! extern crate cgmath; @@ -45,7 +47,7 @@ //! // ┬─┬ノ( º _ ºノ) //! }; //! # } -//! ``` +//! ` ` ` /// Force a conversion into a 2-element array. #[inline] diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/euler.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/euler.rs old mode 100755 new mode 100644 similarity index 97% rename from third_party/cargo/vendor/cgmath-0.17.0/src/euler.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/euler.rs index f281e3d..1e66bb2 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/euler.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/euler.rs @@ -13,18 +13,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -use rand::distributions::{Distribution, Standard}; -use rand::Rng; use num_traits::cast; +#[cfg(feature = "rand")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; use structure::*; use angle::Rad; use approx; -use quaternion::Quaternion; #[cfg(feature = "mint")] use mint; use num::BaseFloat; +use quaternion::Quaternion; /// A set of [Euler angles] representing a rotation in three-dimensional space. /// @@ -186,9 +189,12 @@ impl approx::UlpsEq for Euler { } } +#[cfg(feature = "rand")] impl Distribution> for Standard - where Standard: Distribution, - A: Angle { +where + Standard: Distribution, + A: Angle, +{ fn sample(&self, rng: &mut R) -> Euler { Euler { x: rng.gen(), diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/lib.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/lib.rs new file mode 100644 index 0000000..b9642cb --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/lib.rs @@ -0,0 +1,117 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A low-dimensional linear algebra library, targeted at computer graphics. +//! +//! # Trait overview +//! +//! In order to make a clean, composable API, we divide operations into traits +//! that are roughly based on mathematical properties. The main ones that we +//! concern ourselves with are listed below: +//! +//! - `VectorSpace`: Specifies the main operators for vectors, quaternions, and +//! matrices. +//! - `MetricSpace`: For types that have a distance function implemented. +//! - `InnerSpace`: For types that have a dot (or inner) product - ie. vectors or +//! quaternions. This also allows for the definition of operations that are +//! based on the dot product, like finding the magnitude or normalizing. +//! - `EuclideanSpace`: Points in euclidean space, with an associated space of +//! displacement vectors. +//! - `Matrix`: Common operations for matrices of arbitrary dimensions. +//! - `SquareMatrix`: A special trait for matrices where the number of columns +//! equal the number of rows. +//! +//! Other traits are included for practical convenience, for example: +//! +//! - `Array`: For contiguous, indexable arrays of elements, specifically +//! vectors. +//! - `ElementWise`: For element-wise addition, subtraction, multiplication, +//! division, and remainder operations. +//! +//! # The prelude +//! +//! Importing each trait individually can become a chore, so we provide a +//! `prelude` module to allow you to import the main traits all at once. For +//! example: +//! +//! ```rust +//! use cgmath::prelude::*; +//! ``` + +#![cfg_attr(feature = "simd", feature(specialization))] + +#[macro_use] +extern crate approx; + +#[cfg(feature = "mint")] +pub extern crate mint; + +pub extern crate num_traits; +#[cfg(feature = "rand")] +extern crate rand; + +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +#[cfg(feature = "simd")] +extern crate simd; + +// Re-exports + +pub use approx::*; +pub use num::*; +pub use structure::*; + +pub use matrix::{Matrix2, Matrix3, Matrix4}; +pub use quaternion::Quaternion; +pub use vector::{dot, vec1, vec2, vec3, vec4, Vector1, Vector2, Vector3, Vector4}; + +pub use angle::{Deg, Rad}; +pub use euler::Euler; +pub use point::{point1, point2, point3, Point1, Point2, Point3}; +pub use rotation::*; +pub use transform::*; + +pub use projection::*; + +// Modules + +pub mod conv; +pub mod prelude; + +mod macros; + +mod num; +mod structure; + +mod matrix; +mod quaternion; + +#[cfg(feature = "simd")] +mod quaternion_simd; + +mod vector; + +#[cfg(feature = "simd")] +mod vector_simd; + +mod angle; +mod euler; +mod point; +mod rotation; +mod transform; + +mod projection; diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/macros.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/macros.rs new file mode 100644 index 0000000..e3e798c --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/macros.rs @@ -0,0 +1,401 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Utility macros for code generation + +#![macro_use] + +#[cfg(feature = "simd")] +macro_rules! default_fn { + { $($tt:tt)* } => { default fn $( $tt )* }; +} + +#[cfg(not(feature = "simd"))] +macro_rules! default_fn { + { $($tt:tt)* } => { fn $( $tt )* }; +} + +/// Generates a binary operator implementation for the permutations of by-ref and by-val +macro_rules! impl_operator { + // When it is an unary operator + (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty { + fn $op:ident($x:ident) -> $Output:ty { $body:expr } + }) => { + impl<$S: $Constraint> $Op for $Lhs { + type Output = $Output; + #[inline] + default_fn!($op(self) -> $Output { + let $x = self; $body + }); + } + + impl<'a, $S: $Constraint> $Op for &'a $Lhs { + type Output = $Output; + #[inline] + default_fn!($op(self) -> $Output { + let $x = self; $body + }); + } + }; + // When the right operand is a scalar + (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl<$S: $Constraint> $Op<$Rhs> for $Lhs { + type Output = $Output; + #[inline] + default_fn!($op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + + impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { + type Output = $Output; + #[inline] + default_fn!($op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + }; + // When the right operand is a compound type + (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl<$S: $Constraint> $Op<$Rhs> for $Lhs { + type Output = $Output; + #[inline] + default_fn!( $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + + impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { + type Output = $Output; + #[inline] + default_fn!( $op(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + + impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { + type Output = $Output; + #[inline] + default_fn!( $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + + impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { + type Output = $Output; + #[inline] + default_fn!( $op(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + }; + // When the left operand is a scalar + ($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl $Op<$Rhs<$S>> for $Lhs { + type Output = $Output; + #[inline] + default_fn!( $op(self, other: $Rhs<$S>) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + + impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { + type Output = $Output; + #[inline] + default_fn!( $op(self, other: &'a $Rhs<$S>) -> $Output { + let ($lhs, $rhs) = (self, other); $body + }); + } + }; +} + +macro_rules! impl_assignment_operator { + (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { + fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block + }) => { + impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { + #[inline] + default_fn!( $op(&mut $lhs, $rhs: $Rhs) $body ); + } + }; +} + +macro_rules! fold_array { + (&$method:ident, { $x:expr }) => { + *$x + }; + (&$method:ident, { $x:expr, $y:expr }) => { + $x.$method(&$y) + }; + (&$method:ident, { $x:expr, $y:expr, $z:expr }) => { + $x.$method(&$y).$method(&$z) + }; + (&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { + $x.$method(&$y).$method(&$z).$method(&$w) + }; + ($method:ident, { $x:expr }) => { + $x + }; + ($method:ident, { $x:expr, $y:expr }) => { + $x.$method($y) + }; + ($method:ident, { $x:expr, $y:expr, $z:expr }) => { + $x.$method($y).$method($z) + }; + ($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { + $x.$method($y).$method($z).$method($w) + }; +} + +/// Generate array conversion implementations for a compound array type +macro_rules! impl_fixed_array_conversions { + ($ArrayN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { + impl<$S> Into<[$S; $n]> for $ArrayN<$S> { + #[inline] + fn into(self) -> [$S; $n] { + match self { $ArrayN { $($field),+ } => [$($field),+] } + } + } + + impl<$S> AsRef<[$S; $n]> for $ArrayN<$S> { + #[inline] + fn as_ref(&self) -> &[$S; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<[$S; $n]> for $ArrayN<$S> { + #[inline] + fn as_mut(&mut self) -> &mut [$S; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S: Clone> From<[$S; $n]> for $ArrayN<$S> { + #[inline] + fn from(v: [$S; $n]) -> $ArrayN<$S> { + // We need to use a clone here because we can't pattern match on arrays yet + $ArrayN { $($field: v[$index].clone()),+ } + } + } + + impl<'a, $S> From<&'a [$S; $n]> for &'a $ArrayN<$S> { + #[inline] + fn from(v: &'a [$S; $n]) -> &'a $ArrayN<$S> { + unsafe { mem::transmute(v) } + } + } + + impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $ArrayN<$S> { + #[inline] + fn from(v: &'a mut [$S; $n]) -> &'a mut $ArrayN<$S> { + unsafe { mem::transmute(v) } + } + } + } +} + +/// Generate homogeneous tuple conversion implementations for a compound array type +macro_rules! impl_tuple_conversions { + ($ArrayN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => { + impl<$S> Into<$Tuple> for $ArrayN<$S> { + #[inline] + fn into(self) -> $Tuple { + match self { $ArrayN { $($field),+ } => ($($field),+,) } + } + } + + impl<$S> AsRef<$Tuple> for $ArrayN<$S> { + #[inline] + fn as_ref(&self) -> &$Tuple { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<$Tuple> for $ArrayN<$S> { + #[inline] + fn as_mut(&mut self) -> &mut $Tuple { + unsafe { mem::transmute(self) } + } + } + + impl<$S> From<$Tuple> for $ArrayN<$S> { + #[inline] + fn from(v: $Tuple) -> $ArrayN<$S> { + match v { ($($field),+,) => $ArrayN { $($field: $field),+ } } + } + } + + impl<'a, $S> From<&'a $Tuple> for &'a $ArrayN<$S> { + #[inline] + fn from(v: &'a $Tuple) -> &'a $ArrayN<$S> { + unsafe { mem::transmute(v) } + } + } + + impl<'a, $S> From<&'a mut $Tuple> for &'a mut $ArrayN<$S> { + #[inline] + fn from(v: &'a mut $Tuple) -> &'a mut $ArrayN<$S> { + unsafe { mem::transmute(v) } + } + } + } +} + +/// Generates index operators for a compound type +macro_rules! impl_index_operators { + ($VectorN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { + impl<$S> Index<$I> for $VectorN<$S> { + type Output = $Output; + + #[inline] + fn index<'a>(&'a self, i: $I) -> &'a $Output { + let v: &[$S; $n] = self.as_ref(); + &v[i] + } + } + + impl<$S> IndexMut<$I> for $VectorN<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { + let v: &mut [$S; $n] = self.as_mut(); + &mut v[i] + } + } + }; +} + +/// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd +#[cfg(feature = "simd")] +macro_rules! impl_operator_simd { + // When it is an unary operator + ([$Simd:ident]; $Op:ident for $Lhs:ty { + fn $op:ident($x:ident) -> $Output:ty { $body:expr } + }) => { + impl $Op for $Lhs { + #[inline] + fn $op(self) -> $Output { + let $x: $Simd = self.into(); + $body + } + } + }; + // When the right operand is a scalar + (@rs [$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl $Op<$Rhs> for $Lhs { + #[inline] + fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), $Simd::splat(other)); + $body + } + } + + impl<'a> $Op<$Rhs> for &'a $Lhs { + #[inline] + fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), $Simd::splat(other)); + $body + } + } + }; + + // When the right operand is a compound type + ([$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl $Op<$Rhs> for $Lhs { + #[inline] + fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), other.into()); + $body + } + } + + impl<'a> $Op<&'a $Rhs> for $Lhs { + #[inline] + fn $op(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), (*other).into()); + $body + } + } + + impl<'a> $Op<$Rhs> for &'a $Lhs { + #[inline] + fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), other.into()); + $body + } + } + + impl<'a, 'b> $Op<&'a $Rhs> for &'b $Lhs { + #[inline] + fn $op(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), (*other).into()); + $body + } + } + }; + + // When the left operand is a scalar + (@ls [$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ident { + fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } + }) => { + impl $Op<$Rhs> for $Lhs { + #[inline] + fn $op(self, other: $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), other.into()); + $body + } + } + + impl<'a> $Op<&'a $Rhs> for $Lhs { + #[inline] + fn $op(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), (*other).into()); + $body + } + } + }; +} + +/// Generate `mint` types conversion implementations +#[cfg(feature = "mint")] +macro_rules! impl_mint_conversions { + ($ArrayN:ident { $($field:ident),+ }, $Mint:ident) => { + impl Into> for $ArrayN { + #[inline] + fn into(self) -> mint::$Mint { + mint::$Mint::from([$(self.$field),+]) + } + } + + impl From> for $ArrayN { + #[inline] + fn from(v: mint::$Mint) -> Self { + $ArrayN { $( $field: v.$field, )+ } + } + } + } +} + +include!(concat!(env!("OUT_DIR"), "/swizzle_operator_macro.rs")); diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/matrix.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/matrix.rs new file mode 100644 index 0000000..7245c27 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/matrix.rs @@ -0,0 +1,1798 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use num_traits::{cast, NumCast}; +#[cfg(feature = "rand")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; +use std::fmt; +use std::iter; +use std::mem; +use std::ops::*; +use std::ptr; + +use structure::*; + +use angle::Rad; +use approx; +use euler::Euler; +use num::BaseFloat; +use point::{Point2, Point3}; +use quaternion::Quaternion; +use transform::{Transform, Transform2, Transform3}; +use vector::{Vector2, Vector3, Vector4}; + +#[cfg(feature = "mint")] +use mint; + +/// A 2 x 2, column major matrix +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Matrix2 { + /// The first column of the matrix. + pub x: Vector2, + /// The second column of the matrix. + pub y: Vector2, +} + +/// A 3 x 3, column major matrix +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Matrix3 { + /// The first column of the matrix. + pub x: Vector3, + /// The second column of the matrix. + pub y: Vector3, + /// The third column of the matrix. + pub z: Vector3, +} + +/// A 4 x 4, column major matrix +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Matrix4 { + /// The first column of the matrix. + pub x: Vector4, + /// The second column of the matrix. + pub y: Vector4, + /// The third column of the matrix. + pub z: Vector4, + /// The fourth column of the matrix. + pub w: Vector4, +} + +impl Matrix2 { + /// Create a new matrix, providing values for each index. + #[inline] + pub const fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2 { + Matrix2::from_cols(Vector2::new(c0r0, c0r1), Vector2::new(c1r0, c1r1)) + } + + /// Create a new matrix, providing columns. + #[inline] + pub const fn from_cols(c0: Vector2, c1: Vector2) -> Matrix2 { + Matrix2 { x: c0, y: c1 } + } +} + +impl Matrix2 { + /// Create a transformation matrix that will cause `unit_x()` to point at + /// `dir`. `unit_y()` will be perpendicular to `dir`, and the closest to `up`. + pub fn look_at(dir: Vector2, up: Vector2) -> Matrix2 { + Matrix2::look_at_stable(dir, up.x * dir.y >= up.y * dir.x) + } + + /// Crate a transformation that will cause `unit_x()` to point at + /// `dir`. This is similar to `look_at`, but does not take an `up` vector. + /// This will not cause `unit_y()` to flip when `dir` crosses over the `up` vector. + pub fn look_at_stable(dir: Vector2, flip: bool) -> Matrix2 { + let basis1 = dir.normalize(); + let basis2 = if flip { + Vector2::new(basis1.y, -basis1.x) + } else { + Vector2::new(-basis1.y, basis1.x) + }; + Matrix2::from_cols(basis1, basis2) + } + + #[inline] + pub fn from_angle>>(theta: A) -> Matrix2 { + let (s, c) = Rad::sin_cos(theta.into()); + + Matrix2::new(c, s, -s, c) + } + + /// Are all entries in the matrix finite. + pub fn is_finite(&self) -> bool { + self.x.is_finite() && self.y.is_finite() + } +} + +impl Matrix3 { + /// Create a new matrix, providing values for each index. + #[inline] + #[cfg_attr(rustfmt, rustfmt_skip)] + pub const fn new( + c0r0:S, c0r1:S, c0r2:S, + c1r0:S, c1r1:S, c1r2:S, + c2r0:S, c2r1:S, c2r2:S, + ) -> Matrix3 { + Matrix3::from_cols( + Vector3::new(c0r0, c0r1, c0r2), + Vector3::new(c1r0, c1r1, c1r2), + Vector3::new(c2r0, c2r1, c2r2), + ) + } + + /// Create a new matrix, providing columns. + #[inline] + pub const fn from_cols(c0: Vector3, c1: Vector3, c2: Vector3) -> Matrix3 { + Matrix3 { + x: c0, + y: c1, + z: c2, + } + } +} + +impl Matrix3 { + /// Create a homogeneous transformation matrix from a translation vector. + #[inline] + pub fn from_translation(v: Vector2) -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + S::one(), S::zero(), S::zero(), + S::zero(), S::one(), S::zero(), + v.x, v.y, S::one(), + ) + } + + /// Create a homogeneous transformation matrix from a scale value. + #[inline] + pub fn from_scale(value: S) -> Matrix3 { + Matrix3::from_nonuniform_scale(value, value) + } + + /// Create a homogeneous transformation matrix from a set of scale values. + #[inline] + pub fn from_nonuniform_scale(x: S, y: S) -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + x, S::zero(), S::zero(), + S::zero(), y, S::zero(), + S::zero(), S::zero(), S::one(), + ) + } + + /// Create a rotation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + #[deprecated = "Use Matrix3::look_to_lh"] + pub fn look_at(dir: Vector3, up: Vector3) -> Matrix3 { + Matrix3::look_to_lh(dir, up) + } + + /// Create a rotation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_to_lh(dir: Vector3, up: Vector3) -> Matrix3 { + let dir = dir.normalize(); + let side = up.cross(dir).normalize(); + let up = dir.cross(side).normalize(); + + Matrix3::from_cols(side, up, dir).transpose() + } + + /// Create a rotation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_to_rh(dir: Vector3, up: Vector3) -> Matrix3 { + Matrix3::look_to_lh(-dir, up) + } + + /// Create a rotation matrix from a rotation around the `x` axis (pitch). + pub fn from_angle_x>>(theta: A) -> Matrix3 { + // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + let (s, c) = Rad::sin_cos(theta.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + S::one(), S::zero(), S::zero(), + S::zero(), c, s, + S::zero(), -s, c, + ) + } + + /// Create a rotation matrix from a rotation around the `y` axis (yaw). + pub fn from_angle_y>>(theta: A) -> Matrix3 { + // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + let (s, c) = Rad::sin_cos(theta.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + c, S::zero(), -s, + S::zero(), S::one(), S::zero(), + s, S::zero(), c, + ) + } + + /// Create a rotation matrix from a rotation around the `z` axis (roll). + pub fn from_angle_z>>(theta: A) -> Matrix3 { + // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + let (s, c) = Rad::sin_cos(theta.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + c, s, S::zero(), + -s, c, S::zero(), + S::zero(), S::zero(), S::one(), + ) + } + + /// Create a rotation matrix from an angle around an arbitrary axis. + /// + /// The specified axis **must be normalized**, or it represents an invalid rotation. + pub fn from_axis_angle>>(axis: Vector3, angle: A) -> Matrix3 { + let (s, c) = Rad::sin_cos(angle.into()); + let _1subc = S::one() - c; + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + _1subc * axis.x * axis.x + c, + _1subc * axis.x * axis.y + s * axis.z, + _1subc * axis.x * axis.z - s * axis.y, + + _1subc * axis.x * axis.y - s * axis.z, + _1subc * axis.y * axis.y + c, + _1subc * axis.y * axis.z + s * axis.x, + + _1subc * axis.x * axis.z + s * axis.y, + _1subc * axis.y * axis.z - s * axis.x, + _1subc * axis.z * axis.z + c, + ) + } + + /// Are all entries in the matrix finite. + pub fn is_finite(&self) -> bool { + self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } +} + +impl Matrix4 { + /// Create a new matrix, providing values for each index. + #[inline] + #[cfg_attr(rustfmt, rustfmt_skip)] + pub const fn new( + c0r0: S, c0r1: S, c0r2: S, c0r3: S, + c1r0: S, c1r1: S, c1r2: S, c1r3: S, + c2r0: S, c2r1: S, c2r2: S, c2r3: S, + c3r0: S, c3r1: S, c3r2: S, c3r3: S, + ) -> Matrix4 { + Matrix4::from_cols( + Vector4::new(c0r0, c0r1, c0r2, c0r3), + Vector4::new(c1r0, c1r1, c1r2, c1r3), + Vector4::new(c2r0, c2r1, c2r2, c2r3), + Vector4::new(c3r0, c3r1, c3r2, c3r3), + ) + } + + /// Create a new matrix, providing columns. + #[inline] + pub const fn from_cols( + c0: Vector4, + c1: Vector4, + c2: Vector4, + c3: Vector4, + ) -> Matrix4 { + Matrix4 { + x: c0, + y: c1, + z: c2, + w: c3, + } + } +} + +impl Matrix4 { + /// Create a homogeneous transformation matrix from a translation vector. + #[inline] + pub fn from_translation(v: Vector3) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + S::one(), S::zero(), S::zero(), S::zero(), + S::zero(), S::one(), S::zero(), S::zero(), + S::zero(), S::zero(), S::one(), S::zero(), + v.x, v.y, v.z, S::one(), + ) + } + + /// Create a homogeneous transformation matrix from a scale value. + #[inline] + pub fn from_scale(value: S) -> Matrix4 { + Matrix4::from_nonuniform_scale(value, value, value) + } + + /// Create a homogeneous transformation matrix from a set of scale values. + #[inline] + pub fn from_nonuniform_scale(x: S, y: S, z: S) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + x, S::zero(), S::zero(), S::zero(), + S::zero(), y, S::zero(), S::zero(), + S::zero(), S::zero(), z, S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + #[deprecated = "Use Matrix4::look_to_rh"] + pub fn look_at_dir(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(), + s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(), + s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(), + -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(), + ) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_to_rh(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { + let f = dir.normalize(); + let s = f.cross(up).normalize(); + let u = s.cross(f); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(), + s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(), + s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(), + -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(), + ) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `dir`, using `up` for orientation. + pub fn look_to_lh(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { + Matrix4::look_to_rh(eye, -dir, up) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `center`, using `up` for orientation. + #[deprecated = "Use Matrix4::look_at_rh"] + pub fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_at_rh(eye, center, up) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `center`, using `up` for orientation. + pub fn look_at_rh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_to_rh(eye, center - eye, up) + } + + /// Create a homogeneous transformation matrix that will cause a vector to point at + /// `center`, using `up` for orientation. + pub fn look_at_lh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_to_lh(eye, center - eye, up) + } + + /// Create a homogeneous transformation matrix from a rotation around the `x` axis (pitch). + pub fn from_angle_x>>(theta: A) -> Matrix4 { + // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + let (s, c) = Rad::sin_cos(theta.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + S::one(), S::zero(), S::zero(), S::zero(), + S::zero(), c, s, S::zero(), + S::zero(), -s, c, S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } + + /// Create a homogeneous transformation matrix from a rotation around the `y` axis (yaw). + pub fn from_angle_y>>(theta: A) -> Matrix4 { + // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + let (s, c) = Rad::sin_cos(theta.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + c, S::zero(), -s, S::zero(), + S::zero(), S::one(), S::zero(), S::zero(), + s, S::zero(), c, S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } + + /// Create a homogeneous transformation matrix from a rotation around the `z` axis (roll). + pub fn from_angle_z>>(theta: A) -> Matrix4 { + // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations + let (s, c) = Rad::sin_cos(theta.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + c, s, S::zero(), S::zero(), + -s, c, S::zero(), S::zero(), + S::zero(), S::zero(), S::one(), S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } + + /// Create a homogeneous transformation matrix from an angle around an arbitrary axis. + /// + /// The specified axis **must be normalized**, or it represents an invalid rotation. + pub fn from_axis_angle>>(axis: Vector3, angle: A) -> Matrix4 { + let (s, c) = Rad::sin_cos(angle.into()); + let _1subc = S::one() - c; + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + _1subc * axis.x * axis.x + c, + _1subc * axis.x * axis.y + s * axis.z, + _1subc * axis.x * axis.z - s * axis.y, + S::zero(), + + _1subc * axis.x * axis.y - s * axis.z, + _1subc * axis.y * axis.y + c, + _1subc * axis.y * axis.z + s * axis.x, + S::zero(), + + _1subc * axis.x * axis.z + s * axis.y, + _1subc * axis.y * axis.z - s * axis.x, + _1subc * axis.z * axis.z + c, + S::zero(), + + S::zero(), S::zero(), S::zero(), S::one(), + ) + } + + /// Are all entries in the matrix finite. + pub fn is_finite(&self) -> bool { + self.w.is_finite() && self.x.is_finite() && self.y.is_finite() && self.z.is_finite() + } +} + +impl Zero for Matrix2 { + #[inline] + fn zero() -> Matrix2 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix2::new( + S::zero(), S::zero(), + S::zero(), S::zero(), + ) + } + + #[inline] + fn is_zero(&self) -> bool { + ulps_eq!(self, &Self::zero()) + } +} + +impl Zero for Matrix3 { + #[inline] + fn zero() -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), + ) + } + + #[inline] + fn is_zero(&self) -> bool { + ulps_eq!(self, &Self::zero()) + } +} + +impl Zero for Matrix4 { + #[inline] + fn zero() -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + S::zero(), S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), S::zero(), + S::zero(), S::zero(), S::zero(), S::zero(), + ) + } + + #[inline] + fn is_zero(&self) -> bool { + ulps_eq!(self, &Self::zero()) + } +} + +impl One for Matrix2 { + #[inline] + fn one() -> Matrix2 { + Matrix2::from_value(S::one()) + } +} + +impl One for Matrix3 { + #[inline] + fn one() -> Matrix3 { + Matrix3::from_value(S::one()) + } +} + +impl One for Matrix4 { + #[inline] + fn one() -> Matrix4 { + Matrix4::from_value(S::one()) + } +} + +impl VectorSpace for Matrix2 { + type Scalar = S; +} + +impl VectorSpace for Matrix3 { + type Scalar = S; +} + +impl VectorSpace for Matrix4 { + type Scalar = S; +} + +impl Matrix for Matrix2 { + type Column = Vector2; + type Row = Vector2; + type Transpose = Matrix2; + + #[inline] + fn row(&self, r: usize) -> Vector2 { + Vector2::new(self[0][r], self[1][r]) + } + + #[inline] + fn swap_rows(&mut self, a: usize, b: usize) { + self[0].swap_elements(a, b); + self[1].swap_elements(a, b); + } + + #[inline] + fn swap_columns(&mut self, a: usize, b: usize) { + unsafe { ptr::swap(&mut self[a], &mut self[b]) }; + } + + #[inline] + fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) { + let (ac, ar) = a; + let (bc, br) = b; + unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; + } + + fn transpose(&self) -> Matrix2 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix2::new( + self[0][0], self[1][0], + self[0][1], self[1][1], + ) + } +} + +impl SquareMatrix for Matrix2 { + type ColumnRow = Vector2; + + #[inline] + fn from_value(value: S) -> Matrix2 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix2::new( + value, S::zero(), + S::zero(), value, + ) + } + + #[inline] + fn from_diagonal(value: Vector2) -> Matrix2 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix2::new( + value.x, S::zero(), + S::zero(), value.y, + ) + } + + #[inline] + fn transpose_self(&mut self) { + self.swap_elements((0, 1), (1, 0)); + } + + #[inline] + fn determinant(&self) -> S { + self[0][0] * self[1][1] - self[1][0] * self[0][1] + } + + #[inline] + fn diagonal(&self) -> Vector2 { + Vector2::new(self[0][0], self[1][1]) + } + + #[inline] + fn invert(&self) -> Option> { + let det = self.determinant(); + if det == S::zero() { + None + } else { + #[cfg_attr(rustfmt, rustfmt_skip)] + Some(Matrix2::new( + self[1][1] / det, -self[0][1] / det, + -self[1][0] / det, self[0][0] / det, + )) + } + } + + #[inline] + fn is_diagonal(&self) -> bool { + ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero()) + } + + #[inline] + fn is_symmetric(&self) -> bool { + ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[1][0], &self[0][1]) + } +} + +impl Matrix for Matrix3 { + type Column = Vector3; + type Row = Vector3; + type Transpose = Matrix3; + + #[inline] + fn row(&self, r: usize) -> Vector3 { + Vector3::new(self[0][r], self[1][r], self[2][r]) + } + + #[inline] + fn swap_rows(&mut self, a: usize, b: usize) { + self[0].swap_elements(a, b); + self[1].swap_elements(a, b); + self[2].swap_elements(a, b); + } + + #[inline] + fn swap_columns(&mut self, a: usize, b: usize) { + unsafe { ptr::swap(&mut self[a], &mut self[b]) }; + } + + #[inline] + fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) { + let (ac, ar) = a; + let (bc, br) = b; + unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; + } + + fn transpose(&self) -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + self[0][0], self[1][0], self[2][0], + self[0][1], self[1][1], self[2][1], + self[0][2], self[1][2], self[2][2], + ) + } +} + +impl SquareMatrix for Matrix3 { + type ColumnRow = Vector3; + + #[inline] + fn from_value(value: S) -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + value, S::zero(), S::zero(), + S::zero(), value, S::zero(), + S::zero(), S::zero(), value, + ) + } + + #[inline] + fn from_diagonal(value: Vector3) -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + value.x, S::zero(), S::zero(), + S::zero(), value.y, S::zero(), + S::zero(), S::zero(), value.z, + ) + } + + #[inline] + fn transpose_self(&mut self) { + self.swap_elements((0, 1), (1, 0)); + self.swap_elements((0, 2), (2, 0)); + self.swap_elements((1, 2), (2, 1)); + } + + fn determinant(&self) -> S { + self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2]) + - self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2]) + + self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2]) + } + + #[inline] + fn diagonal(&self) -> Vector3 { + Vector3::new(self[0][0], self[1][1], self[2][2]) + } + + fn invert(&self) -> Option> { + let det = self.determinant(); + if det == S::zero() { + None + } else { + Some( + Matrix3::from_cols( + self[1].cross(self[2]) / det, + self[2].cross(self[0]) / det, + self[0].cross(self[1]) / det, + ) + .transpose(), + ) + } + } + + fn is_diagonal(&self) -> bool { + ulps_eq!(self[0][1], &S::zero()) + && ulps_eq!(self[0][2], &S::zero()) + && ulps_eq!(self[1][0], &S::zero()) + && ulps_eq!(self[1][2], &S::zero()) + && ulps_eq!(self[2][0], &S::zero()) + && ulps_eq!(self[2][1], &S::zero()) + } + + fn is_symmetric(&self) -> bool { + ulps_eq!(self[0][1], &self[1][0]) + && ulps_eq!(self[0][2], &self[2][0]) + && ulps_eq!(self[1][0], &self[0][1]) + && ulps_eq!(self[1][2], &self[2][1]) + && ulps_eq!(self[2][0], &self[0][2]) + && ulps_eq!(self[2][1], &self[1][2]) + } +} + +impl Matrix for Matrix4 { + type Column = Vector4; + type Row = Vector4; + type Transpose = Matrix4; + + #[inline] + fn row(&self, r: usize) -> Vector4 { + Vector4::new(self[0][r], self[1][r], self[2][r], self[3][r]) + } + + #[inline] + fn swap_rows(&mut self, a: usize, b: usize) { + self[0].swap_elements(a, b); + self[1].swap_elements(a, b); + self[2].swap_elements(a, b); + self[3].swap_elements(a, b); + } + + #[inline] + fn swap_columns(&mut self, a: usize, b: usize) { + unsafe { ptr::swap(&mut self[a], &mut self[b]) }; + } + + #[inline] + fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) { + let (ac, ar) = a; + let (bc, br) = b; + unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; + } + + fn transpose(&self) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + self[0][0], self[1][0], self[2][0], self[3][0], + self[0][1], self[1][1], self[2][1], self[3][1], + self[0][2], self[1][2], self[2][2], self[3][2], + self[0][3], self[1][3], self[2][3], self[3][3], + ) + } +} + +impl SquareMatrix for Matrix4 { + type ColumnRow = Vector4; + + #[inline] + fn from_value(value: S) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + value, S::zero(), S::zero(), S::zero(), + S::zero(), value, S::zero(), S::zero(), + S::zero(), S::zero(), value, S::zero(), + S::zero(), S::zero(), S::zero(), value, + ) + } + + #[inline] + fn from_diagonal(value: Vector4) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + value.x, S::zero(), S::zero(), S::zero(), + S::zero(), value.y, S::zero(), S::zero(), + S::zero(), S::zero(), value.z, S::zero(), + S::zero(), S::zero(), S::zero(), value.w, + ) + } + + fn transpose_self(&mut self) { + self.swap_elements((0, 1), (1, 0)); + self.swap_elements((0, 2), (2, 0)); + self.swap_elements((0, 3), (3, 0)); + self.swap_elements((1, 2), (2, 1)); + self.swap_elements((1, 3), (3, 1)); + self.swap_elements((2, 3), (3, 2)); + } + + fn determinant(&self) -> S { + let tmp = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) }; + tmp.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0])) + } + + #[inline] + fn diagonal(&self) -> Vector4 { + Vector4::new(self[0][0], self[1][1], self[2][2], self[3][3]) + } + + // The new implementation results in negative optimization when used + // without SIMD. so we opt them in with configuration. + // A better option would be using specialization. But currently somewhat + // specialization is too buggy, and it won't apply here. I'm getting + // weird error msgs. Help wanted. + #[cfg(not(feature = "simd"))] + fn invert(&self) -> Option> { + let det = self.determinant(); + if det == S::zero() { + None + } else { + let inv_det = S::one() / det; + let t = self.transpose(); + let cf = |i, j| { + let mat = match i { + 0 => { + Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)) + } + 1 => { + Matrix3::from_cols(t.x.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)) + } + 2 => { + Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.w.truncate_n(j)) + } + 3 => { + Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.z.truncate_n(j)) + } + _ => panic!("out of range"), + }; + let sign = if (i + j) & 1 == 1 { + -S::one() + } else { + S::one() + }; + mat.determinant() * sign * inv_det + }; + + #[cfg_attr(rustfmt, rustfmt_skip)] + Some(Matrix4::new( + cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3), + cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3), + cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3), + cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3), + )) + } + } + #[cfg(feature = "simd")] + fn invert(&self) -> Option> { + let tmp0 = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) }; + let det = tmp0.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0])); + + if det == S::zero() { + None + } else { + let inv_det = S::one() / det; + let tmp0 = tmp0 * inv_det; + let tmp1 = unsafe { det_sub_proc_unsafe(self, 0, 3, 2) * inv_det }; + let tmp2 = unsafe { det_sub_proc_unsafe(self, 0, 1, 3) * inv_det }; + let tmp3 = unsafe { det_sub_proc_unsafe(self, 0, 2, 1) * inv_det }; + Some(Matrix4::from_cols(tmp0, tmp1, tmp2, tmp3)) + } + } + + fn is_diagonal(&self) -> bool { + ulps_eq!(self[0][1], &S::zero()) + && ulps_eq!(self[0][2], &S::zero()) + && ulps_eq!(self[0][3], &S::zero()) + && ulps_eq!(self[1][0], &S::zero()) + && ulps_eq!(self[1][2], &S::zero()) + && ulps_eq!(self[1][3], &S::zero()) + && ulps_eq!(self[2][0], &S::zero()) + && ulps_eq!(self[2][1], &S::zero()) + && ulps_eq!(self[2][3], &S::zero()) + && ulps_eq!(self[3][0], &S::zero()) + && ulps_eq!(self[3][1], &S::zero()) + && ulps_eq!(self[3][2], &S::zero()) + } + + fn is_symmetric(&self) -> bool { + ulps_eq!(self[0][1], &self[1][0]) + && ulps_eq!(self[0][2], &self[2][0]) + && ulps_eq!(self[0][3], &self[3][0]) + && ulps_eq!(self[1][0], &self[0][1]) + && ulps_eq!(self[1][2], &self[2][1]) + && ulps_eq!(self[1][3], &self[3][1]) + && ulps_eq!(self[2][0], &self[0][2]) + && ulps_eq!(self[2][1], &self[1][2]) + && ulps_eq!(self[2][3], &self[3][2]) + && ulps_eq!(self[3][0], &self[0][3]) + && ulps_eq!(self[3][1], &self[1][3]) + && ulps_eq!(self[3][2], &self[2][3]) + } +} + +impl approx::AbsDiffEq for Matrix2 { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + cast(1.0e-6f64).unwrap() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + Vector2::abs_diff_eq(&self[0], &other[0], epsilon) + && Vector2::abs_diff_eq(&self[1], &other[1], epsilon) + } +} + +impl approx::RelativeEq for Matrix2 { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + Vector2::relative_eq(&self[0], &other[0], epsilon, max_relative) + && Vector2::relative_eq(&self[1], &other[1], epsilon, max_relative) + } +} + +impl approx::UlpsEq for Matrix2 { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + Vector2::ulps_eq(&self[0], &other[0], epsilon, max_ulps) + && Vector2::ulps_eq(&self[1], &other[1], epsilon, max_ulps) + } +} + +impl approx::AbsDiffEq for Matrix3 { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + cast(1.0e-6f64).unwrap() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + Vector3::abs_diff_eq(&self[0], &other[0], epsilon) + && Vector3::abs_diff_eq(&self[1], &other[1], epsilon) + && Vector3::abs_diff_eq(&self[2], &other[2], epsilon) + } +} + +impl approx::RelativeEq for Matrix3 { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + Vector3::relative_eq(&self[0], &other[0], epsilon, max_relative) + && Vector3::relative_eq(&self[1], &other[1], epsilon, max_relative) + && Vector3::relative_eq(&self[2], &other[2], epsilon, max_relative) + } +} + +impl approx::UlpsEq for Matrix3 { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + Vector3::ulps_eq(&self[0], &other[0], epsilon, max_ulps) + && Vector3::ulps_eq(&self[1], &other[1], epsilon, max_ulps) + && Vector3::ulps_eq(&self[2], &other[2], epsilon, max_ulps) + } +} + +impl approx::AbsDiffEq for Matrix4 { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + cast(1.0e-6f64).unwrap() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + Vector4::abs_diff_eq(&self[0], &other[0], epsilon) + && Vector4::abs_diff_eq(&self[1], &other[1], epsilon) + && Vector4::abs_diff_eq(&self[2], &other[2], epsilon) + && Vector4::abs_diff_eq(&self[3], &other[3], epsilon) + } +} + +impl approx::RelativeEq for Matrix4 { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + Vector4::relative_eq(&self[0], &other[0], epsilon, max_relative) + && Vector4::relative_eq(&self[1], &other[1], epsilon, max_relative) + && Vector4::relative_eq(&self[2], &other[2], epsilon, max_relative) + && Vector4::relative_eq(&self[3], &other[3], epsilon, max_relative) + } +} + +impl approx::UlpsEq for Matrix4 { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + Vector4::ulps_eq(&self[0], &other[0], epsilon, max_ulps) + && Vector4::ulps_eq(&self[1], &other[1], epsilon, max_ulps) + && Vector4::ulps_eq(&self[2], &other[2], epsilon, max_ulps) + && Vector4::ulps_eq(&self[3], &other[3], epsilon, max_ulps) + } +} + +impl Transform> for Matrix3 { + fn look_at(eye: Point2, center: Point2, up: Vector2) -> Matrix3 { + let dir = center - eye; + Matrix3::from(Matrix2::look_at(dir, up)) + } + + fn look_at_lh(eye: Point2, center: Point2, up: Vector2) -> Matrix3 { + let dir = center - eye; + Matrix3::from(Matrix2::look_at(dir, up)) + } + + fn look_at_rh(eye: Point2, center: Point2, up: Vector2) -> Matrix3 { + let dir = eye - center; + Matrix3::from(Matrix2::look_at(dir, up)) + } + + fn transform_vector(&self, vec: Vector2) -> Vector2 { + (self * vec.extend(S::zero())).truncate() + } + + fn transform_point(&self, point: Point2) -> Point2 { + Point2::from_vec((self * Point3::new(point.x, point.y, S::one()).to_vec()).truncate()) + } + + fn concat(&self, other: &Matrix3) -> Matrix3 { + self * other + } + + fn inverse_transform(&self) -> Option> { + SquareMatrix::invert(self) + } +} + +impl Transform> for Matrix3 { + fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix3 { + let dir = center - eye; + Matrix3::look_to_lh(dir, up) + } + + fn look_at_lh(eye: Point3, center: Point3, up: Vector3) -> Matrix3 { + let dir = center - eye; + Matrix3::look_to_lh(dir, up) + } + + fn look_at_rh(eye: Point3, center: Point3, up: Vector3) -> Matrix3 { + let dir = center - eye; + Matrix3::look_to_rh(dir, up) + } + + fn transform_vector(&self, vec: Vector3) -> Vector3 { + self * vec + } + + fn transform_point(&self, point: Point3) -> Point3 { + Point3::from_vec(self * point.to_vec()) + } + + fn concat(&self, other: &Matrix3) -> Matrix3 { + self * other + } + + fn inverse_transform(&self) -> Option> { + SquareMatrix::invert(self) + } +} + +impl Transform> for Matrix4 { + + fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_at_rh(eye, center, up) + } + + fn look_at_lh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_at_lh(eye, center, up) + } + + fn look_at_rh(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { + Matrix4::look_at_rh(eye, center, up) + } + + fn transform_vector(&self, vec: Vector3) -> Vector3 { + (self * vec.extend(S::zero())).truncate() + } + + fn transform_point(&self, point: Point3) -> Point3 { + Point3::from_homogeneous(self * point.to_homogeneous()) + } + + fn concat(&self, other: &Matrix4) -> Matrix4 { + self * other + } + + fn inverse_transform(&self) -> Option> { + SquareMatrix::invert(self) + } +} + +impl Transform2 for Matrix3 { + type Scalar = S; +} + +impl Transform3 for Matrix3 { + type Scalar = S; +} + +impl Transform3 for Matrix4 { + type Scalar = S; +} + +macro_rules! impl_matrix { + ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => { + impl_operator!( Neg for $MatrixN { + fn neg(matrix) -> $MatrixN { $MatrixN { $($field: -matrix.$field),+ } } + }); + + impl_operator!( Mul for $MatrixN { + fn mul(matrix, scalar) -> $MatrixN { $MatrixN { $($field: matrix.$field * scalar),+ } } + }); + impl_operator!( Div for $MatrixN { + fn div(matrix, scalar) -> $MatrixN { $MatrixN { $($field: matrix.$field / scalar),+ } } + }); + impl_operator!( Rem for $MatrixN { + fn rem(matrix, scalar) -> $MatrixN { $MatrixN { $($field: matrix.$field % scalar),+ } } + }); + impl_assignment_operator!( MulAssign for $MatrixN { + fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } + }); + impl_assignment_operator!( DivAssign for $MatrixN { + fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } + }); + impl_assignment_operator!( RemAssign for $MatrixN { + fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } + }); + + impl_operator!( Add<$MatrixN > for $MatrixN { + fn add(lhs, rhs) -> $MatrixN { $MatrixN { $($field: lhs.$field + rhs.$field),+ } } + }); + impl_operator!( Sub<$MatrixN > for $MatrixN { + fn sub(lhs, rhs) -> $MatrixN { $MatrixN { $($field: lhs.$field - rhs.$field),+ } } + }); + impl> AddAssign<$MatrixN> for $MatrixN { + fn add_assign(&mut self, other: $MatrixN) { $(self.$field += other.$field);+ } + } + impl> SubAssign<$MatrixN> for $MatrixN { + fn sub_assign(&mut self, other: $MatrixN) { $(self.$field -= other.$field);+ } + } + + impl iter::Sum<$MatrixN> for $MatrixN { + #[inline] + fn sum>>(iter: I) -> $MatrixN { + iter.fold($MatrixN::zero(), Add::add) + } + } + + impl<'a, S: 'a + BaseFloat> iter::Sum<&'a $MatrixN> for $MatrixN { + #[inline] + fn sum>>(iter: I) -> $MatrixN { + iter.fold($MatrixN::zero(), Add::add) + } + } + + impl iter::Product for $MatrixN { + #[inline] + fn product>>(iter: I) -> $MatrixN { + iter.fold($MatrixN::identity(), Mul::mul) + } + } + + impl<'a, S: 'a + BaseFloat> iter::Product<&'a $MatrixN> for $MatrixN { + #[inline] + fn product>>(iter: I) -> $MatrixN { + iter.fold($MatrixN::identity(), Mul::mul) + } + } + + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + impl_scalar_ops!($MatrixN { $($field),+ }); + + + impl $MatrixN { + /// Component-wise casting to another type + #[inline] + pub fn cast(&self) -> Option<$MatrixN> { + $( + let $field = match self.$field.cast() { + Some(field) => field, + None => return None + }; + )+ + Some($MatrixN { $($field),+ }) + } + } + } +} + +macro_rules! impl_scalar_ops { + ($MatrixN:ident<$S:ident> { $($field:ident),+ }) => { + impl_operator!(Mul<$MatrixN<$S>> for $S { + fn mul(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar * matrix.$field),+ } } + }); + impl_operator!(Div<$MatrixN<$S>> for $S { + fn div(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar / matrix.$field),+ } } + }); + impl_operator!(Rem<$MatrixN<$S>> for $S { + fn rem(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar % matrix.$field),+ } } + }); + }; +} + +impl_matrix!(Matrix2, Vector2 { x: 0, y: 1 }); +impl_matrix!(Matrix3, Vector3 { x: 0, y: 1, z: 2 }); +#[cfg_attr(rustfmt, rustfmt_skip)] +impl_matrix!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 }); + +macro_rules! impl_mv_operator { + ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => { + impl_operator!( Mul<$VectorN > for $MatrixN { + fn mul(matrix, vector) -> $VectorN {$VectorN::new($(matrix.row($row_index).dot(vector.clone())),+)} + }); + } +} + +impl_mv_operator!(Matrix2, Vector2 { x: 0, y: 1 }); +impl_mv_operator!(Matrix3, Vector3 { x: 0, y: 1, z: 2 }); +#[cfg(not(feature = "simd"))] +#[cfg_attr(rustfmt, rustfmt_skip)] +impl_mv_operator!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 }); + +#[cfg(feature = "simd")] +impl_operator!( Mul > for Matrix4 { + fn mul(matrix, vector) -> Vector4 { + matrix[0] * vector[0] + matrix[1] * vector[1] + matrix[2] * vector[2] + matrix[3] * vector[3] + } +}); + +impl_operator!( Mul > for Matrix2 { + fn mul(lhs, rhs) -> Matrix2 { + Matrix2::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]), + lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1])) + } +}); + +impl_operator!( Mul > for Matrix3 { + fn mul(lhs, rhs) -> Matrix3 { + Matrix3::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]), lhs.row(2).dot(rhs[0]), + lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1]), lhs.row(2).dot(rhs[1]), + lhs.row(0).dot(rhs[2]), lhs.row(1).dot(rhs[2]), lhs.row(2).dot(rhs[2])) + } +}); + +// Using self.row(0).dot(other[0]) like the other matrix multiplies +// causes the LLVM to miss identical loads and multiplies. This optimization +// causes the code to be auto vectorized properly increasing the performance +// around ~4 times. +// Update: this should now be a bit more efficient + +impl_operator!( Mul > for Matrix4 { + fn mul(lhs, rhs) -> Matrix4 { + { + let a = lhs[0]; + let b = lhs[1]; + let c = lhs[2]; + let d = lhs[3]; + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::from_cols( + a*rhs[0][0] + b*rhs[0][1] + c*rhs[0][2] + d*rhs[0][3], + a*rhs[1][0] + b*rhs[1][1] + c*rhs[1][2] + d*rhs[1][3], + a*rhs[2][0] + b*rhs[2][1] + c*rhs[2][2] + d*rhs[2][3], + a*rhs[3][0] + b*rhs[3][1] + c*rhs[3][2] + d*rhs[3][3], + ) + } + } +}); + +macro_rules! index_operators { + ($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { + impl<$S> Index<$I> for $MatrixN<$S> { + type Output = $Output; + + #[inline] + fn index<'a>(&'a self, i: $I) -> &'a $Output { + let v: &[[$S; $n]; $n] = self.as_ref(); + From::from(&v[i]) + } + } + + impl<$S> IndexMut<$I> for $MatrixN<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { + let v: &mut [[$S; $n]; $n] = self.as_mut(); + From::from(&mut v[i]) + } + } + }; +} + +index_operators!(Matrix2, 2, Vector2, usize); +index_operators!(Matrix3, 3, Vector3, usize); +index_operators!(Matrix4, 4, Vector4, usize); +// index_operators!(Matrix2, 2, [Vector2], Range); +// index_operators!(Matrix3, 3, [Vector3], Range); +// index_operators!(Matrix4, 4, [Vector4], Range); +// index_operators!(Matrix2, 2, [Vector2], RangeTo); +// index_operators!(Matrix3, 3, [Vector3], RangeTo); +// index_operators!(Matrix4, 4, [Vector4], RangeTo); +// index_operators!(Matrix2, 2, [Vector2], RangeFrom); +// index_operators!(Matrix3, 3, [Vector3], RangeFrom); +// index_operators!(Matrix4, 4, [Vector4], RangeFrom); +// index_operators!(Matrix2, 2, [Vector2], RangeFull); +// index_operators!(Matrix3, 3, [Vector3], RangeFull); +// index_operators!(Matrix4, 4, [Vector4], RangeFull); + +impl From> for Matrix3 +where + A: Angle + Into::Unitless>>, +{ + fn from(src: Euler) -> Matrix3 { + // Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf + let (sx, cx) = Rad::sin_cos(src.x.into()); + let (sy, cy) = Rad::sin_cos(src.y.into()); + let (sz, cz) = Rad::sin_cos(src.z.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, + -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, + sy, -sx * cy, cx * cy, + ) + } +} + +impl From> for Matrix4 +where + A: Angle + Into::Unitless>>, +{ + fn from(src: Euler) -> Matrix4 { + // Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf + let (sx, cx) = Rad::sin_cos(src.x.into()); + let (sy, cy) = Rad::sin_cos(src.y.into()); + let (sz, cz) = Rad::sin_cos(src.z.into()); + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, A::Unitless::zero(), + -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, A::Unitless::zero(), + sy, -sx * cy, cx * cy, A::Unitless::zero(), + A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one(), + ) + } +} + +macro_rules! fixed_array_conversions { + ($MatrixN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { + impl<$S> Into<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn into(self) -> [[$S; $n]; $n] { + match self { $MatrixN { $($field),+ } => [$($field.into()),+] } + } + } + + impl<$S> AsRef<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn as_ref(&self) -> &[[$S; $n]; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn as_mut(&mut self) -> &mut [[$S; $n]; $n] { + unsafe { mem::transmute(self) } + } + } + + impl<$S: Copy> From<[[$S; $n]; $n]> for $MatrixN<$S> { + #[inline] + fn from(m: [[$S; $n]; $n]) -> $MatrixN<$S> { + // We need to use a copy here because we can't pattern match on arrays yet + $MatrixN { $($field: From::from(m[$index])),+ } + } + } + + impl<'a, $S> From<&'a [[$S; $n]; $n]> for &'a $MatrixN<$S> { + #[inline] + fn from(m: &'a [[$S; $n]; $n]) -> &'a $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + + impl<'a, $S> From<&'a mut [[$S; $n]; $n]> for &'a mut $MatrixN<$S> { + #[inline] + fn from(m: &'a mut [[$S; $n]; $n]) -> &'a mut $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + + // impl<$S> Into<[$S; ($n * $n)]> for $MatrixN<$S> { + // #[inline] + // fn into(self) -> [[$S; $n]; $n] { + // // TODO: Not sure how to implement this... + // unimplemented!() + // } + // } + + impl<$S> AsRef<[$S; ($n * $n)]> for $MatrixN<$S> { + #[inline] + fn as_ref(&self) -> &[$S; ($n * $n)] { + unsafe { mem::transmute(self) } + } + } + + impl<$S> AsMut<[$S; ($n * $n)]> for $MatrixN<$S> { + #[inline] + fn as_mut(&mut self) -> &mut [$S; ($n * $n)] { + unsafe { mem::transmute(self) } + } + } + + // impl<$S> From<[$S; ($n * $n)]> for $MatrixN<$S> { + // #[inline] + // fn from(m: [$S; ($n * $n)]) -> $MatrixN<$S> { + // // TODO: Not sure how to implement this... + // unimplemented!() + // } + // } + + impl<'a, $S> From<&'a [$S; ($n * $n)]> for &'a $MatrixN<$S> { + #[inline] + fn from(m: &'a [$S; ($n * $n)]) -> &'a $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + + impl<'a, $S> From<&'a mut [$S; ($n * $n)]> for &'a mut $MatrixN<$S> { + #[inline] + fn from(m: &'a mut [$S; ($n * $n)]) -> &'a mut $MatrixN<$S> { + unsafe { mem::transmute(m) } + } + } + } +} + +fixed_array_conversions!(Matrix2 { x:0, y:1 }, 2); +fixed_array_conversions!(Matrix3 { x:0, y:1, z:2 }, 3); +fixed_array_conversions!(Matrix4 { x:0, y:1, z:2, w:3 }, 4); + +#[cfg(feature = "mint")] +macro_rules! mint_conversions { + ($MatrixN:ident { $($field:ident),+ }, $MintN:ident) => { + impl Into> for $MatrixN { + #[inline] + fn into(self) -> mint::$MintN { + mint::$MintN { $($field: self.$field.into()),+ } + } + } + + impl From> for $MatrixN { + #[inline] + fn from(m: mint::$MintN) -> Self { + $MatrixN { $($field: m.$field.into()),+ } + } + } + + } +} + +#[cfg(feature = "mint")] +mint_conversions!(Matrix2 { x, y }, ColumnMatrix2); +#[cfg(feature = "mint")] +mint_conversions!(Matrix3 { x, y, z }, ColumnMatrix3); +#[cfg(feature = "mint")] +mint_conversions!(Matrix4 { x, y, z, w }, ColumnMatrix4); + +impl From> for Matrix3 { + /// Clone the elements of a 2-dimensional matrix into the top-left corner + /// of a 3-dimensional identity matrix. + fn from(m: Matrix2) -> Matrix3 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + m[0][0], m[0][1], S::zero(), + m[1][0], m[1][1], S::zero(), + S::zero(), S::zero(), S::one(), + ) + } +} + +impl From> for Matrix4 { + /// Clone the elements of a 2-dimensional matrix into the top-left corner + /// of a 4-dimensional identity matrix. + fn from(m: Matrix2) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + m[0][0], m[0][1], S::zero(), S::zero(), + m[1][0], m[1][1], S::zero(), S::zero(), + S::zero(), S::zero(), S::one(), S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } +} + +impl From> for Matrix4 { + /// Clone the elements of a 3-dimensional matrix into the top-left corner + /// of a 4-dimensional identity matrix. + fn from(m: Matrix3) -> Matrix4 { + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + m[0][0], m[0][1], m[0][2], S::zero(), + m[1][0], m[1][1], m[1][2], S::zero(), + m[2][0], m[2][1], m[2][2], S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } +} + +impl From> for Quaternion { + /// Convert the matrix to a quaternion + fn from(mat: Matrix3) -> Quaternion { + // http://www.cs.ucr.edu/~vbz/resources/quatut.pdf + let trace = mat.trace(); + let half: S = cast(0.5f64).unwrap(); + + if trace >= S::zero() { + let s = (S::one() + trace).sqrt(); + let w = half * s; + let s = half / s; + let x = (mat[1][2] - mat[2][1]) * s; + let y = (mat[2][0] - mat[0][2]) * s; + let z = (mat[0][1] - mat[1][0]) * s; + Quaternion::new(w, x, y, z) + } else if (mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2]) { + let s = ((mat[0][0] - mat[1][1] - mat[2][2]) + S::one()).sqrt(); + let x = half * s; + let s = half / s; + let y = (mat[1][0] + mat[0][1]) * s; + let z = (mat[0][2] + mat[2][0]) * s; + let w = (mat[1][2] - mat[2][1]) * s; + Quaternion::new(w, x, y, z) + } else if mat[1][1] > mat[2][2] { + let s = ((mat[1][1] - mat[0][0] - mat[2][2]) + S::one()).sqrt(); + let y = half * s; + let s = half / s; + let z = (mat[2][1] + mat[1][2]) * s; + let x = (mat[1][0] + mat[0][1]) * s; + let w = (mat[2][0] - mat[0][2]) * s; + Quaternion::new(w, x, y, z) + } else { + let s = ((mat[2][2] - mat[0][0] - mat[1][1]) + S::one()).sqrt(); + let z = half * s; + let s = half / s; + let x = (mat[0][2] + mat[2][0]) * s; + let y = (mat[2][1] + mat[1][2]) * s; + let w = (mat[0][1] - mat[1][0]) * s; + Quaternion::new(w, x, y, z) + } + } +} + +impl fmt::Debug for Matrix2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Matrix2 ")?; + <[[S; 2]; 2] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Matrix3 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Matrix3 ")?; + <[[S; 3]; 3] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Matrix4 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Matrix4 ")?; + <[[S; 4]; 4] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +#[cfg(feature = "rand")] +impl Distribution> for Standard +where + Standard: Distribution>, + S: BaseFloat, +{ + #[inline] + fn sample(&self, rng: &mut R) -> Matrix2 { + Matrix2 { + x: self.sample(rng), + y: self.sample(rng), + } + } +} + +#[cfg(feature = "rand")] +impl Distribution> for Standard +where + Standard: Distribution>, + S: BaseFloat, +{ + #[inline] + fn sample(&self, rng: &mut R) -> Matrix3 { + Matrix3 { + x: rng.gen(), + y: rng.gen(), + z: rng.gen(), + } + } +} + +#[cfg(feature = "rand")] +impl Distribution> for Standard +where + Standard: Distribution>, + S: BaseFloat, +{ + #[inline] + fn sample(&self, rng: &mut R) -> Matrix4 { + Matrix4 { + x: rng.gen(), + y: rng.gen(), + z: rng.gen(), + w: rng.gen(), + } + } +} + +// Sub procedure for SIMD when dealing with determinant and inversion +#[inline] +unsafe fn det_sub_proc_unsafe( + m: &Matrix4, + x: usize, + y: usize, + z: usize, +) -> Vector4 { + let s: &[S; 16] = m.as_ref(); + let a = Vector4::new( + *s.get_unchecked(4 + x), + *s.get_unchecked(12 + x), + *s.get_unchecked(x), + *s.get_unchecked(8 + x), + ); + let b = Vector4::new( + *s.get_unchecked(8 + y), + *s.get_unchecked(8 + y), + *s.get_unchecked(4 + y), + *s.get_unchecked(4 + y), + ); + let c = Vector4::new( + *s.get_unchecked(12 + z), + *s.get_unchecked(z), + *s.get_unchecked(12 + z), + *s.get_unchecked(z), + ); + + let d = Vector4::new( + *s.get_unchecked(8 + x), + *s.get_unchecked(8 + x), + *s.get_unchecked(4 + x), + *s.get_unchecked(4 + x), + ); + let e = Vector4::new( + *s.get_unchecked(12 + y), + *s.get_unchecked(y), + *s.get_unchecked(12 + y), + *s.get_unchecked(y), + ); + let f = Vector4::new( + *s.get_unchecked(4 + z), + *s.get_unchecked(12 + z), + *s.get_unchecked(z), + *s.get_unchecked(8 + z), + ); + + let g = Vector4::new( + *s.get_unchecked(12 + x), + *s.get_unchecked(x), + *s.get_unchecked(12 + x), + *s.get_unchecked(x), + ); + let h = Vector4::new( + *s.get_unchecked(4 + y), + *s.get_unchecked(12 + y), + *s.get_unchecked(y), + *s.get_unchecked(8 + y), + ); + let i = Vector4::new( + *s.get_unchecked(8 + z), + *s.get_unchecked(8 + z), + *s.get_unchecked(4 + z), + *s.get_unchecked(4 + z), + ); + let mut tmp = a.mul_element_wise(b.mul_element_wise(c)); + tmp += d.mul_element_wise(e.mul_element_wise(f)); + tmp += g.mul_element_wise(h.mul_element_wise(i)); + tmp -= a.mul_element_wise(e.mul_element_wise(i)); + tmp -= d.mul_element_wise(h.mul_element_wise(c)); + tmp -= g.mul_element_wise(b.mul_element_wise(f)); + tmp +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/num.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/num.rs old mode 100755 new mode 100644 similarity index 92% rename from third_party/cargo/vendor/cgmath-0.17.0/src/num.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/num.rs index 113a4f2..3278721 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/num.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/num.rs @@ -36,8 +36,7 @@ pub trait BaseNum: { } -impl BaseNum for T -where +impl BaseNum for T where T: Copy + Clone + fmt::Debug @@ -48,7 +47,7 @@ where + SubAssign + MulAssign + DivAssign - + RemAssign, + + RemAssign { } @@ -62,12 +61,11 @@ pub trait BaseFloat: { } -impl BaseFloat for T -where +impl BaseFloat for T where T: BaseNum + Float + approx::AbsDiffEq + approx::RelativeEq - + approx::UlpsEq, + + approx::UlpsEq { } diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/point.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/point.rs new file mode 100644 index 0000000..faf2a6d --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/point.rs @@ -0,0 +1,618 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Points are fixed positions in affine space with no length or direction. This +//! distinguishes them from vectors, which have a length and direction, but do +//! not have a fixed position. + +use num_traits::{Bounded, Float, NumCast}; +use std::fmt; +use std::mem; +use std::ops::*; + +use structure::*; + +use approx; +use num::{BaseFloat, BaseNum}; +use vector::{Vector1, Vector2, Vector3, Vector4}; + +#[cfg(feature = "mint")] +use mint; + +/// A point in 1-dimensional space. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Point1 { + pub x: S, +} + +/// A point in 2-dimensional space. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Point2 { + pub x: S, + pub y: S, +} + +/// A point in 3-dimensional space. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Point3 { + pub x: S, + pub y: S, + pub z: S, +} + +impl Point3 { + #[inline] + pub fn from_homogeneous(v: Vector4) -> Point3 { + let e = v.truncate() * (S::one() / v.w); + Point3::new(e.x, e.y, e.z) //FIXME + } + + #[inline] + pub fn to_homogeneous(self) -> Vector4 { + Vector4::new(self.x, self.y, self.z, S::one()) + } +} + +macro_rules! impl_point { + ($PointN:ident { $($field:ident),+ }, $VectorN:ident, $n:expr, $constructor:ident) => { + impl $PointN { + /// Construct a new point, using the provided values. + #[inline] + pub const fn new($($field: S),+) -> $PointN { + $PointN { $($field: $field),+ } + } + + /// Perform the given operation on each field in the point, returning a new point + /// constructed from the operations. + #[inline] + pub fn map(self, mut f: F) -> $PointN + where F: FnMut(S) -> U + { + $PointN { $($field: f(self.$field)),+ } + } + + /// Construct a new point where each component is the result of + /// applying the given operation to each pair of components of the + /// given points. + #[inline] + pub fn zip(self, p2: $PointN, mut f: F) -> $PointN + where F: FnMut(S, S2) -> S3 + { + $PointN { $($field: f(self.$field, p2.$field)),+ } + } + } + + /// The short constructor. + #[inline] + pub const fn $constructor($($field: S),+) -> $PointN { + $PointN::new($($field),+) + } + + impl Array for $PointN { + type Element = S; + + #[inline] + fn len() -> usize { + $n + } + + #[inline] + fn from_value(scalar: S) -> $PointN { + $PointN { $($field: scalar),+ } + } + + #[inline] + fn sum(self) -> S where S: Add { + fold_array!(add, { $(self.$field),+ }) + } + + #[inline] + fn product(self) -> S where S: Mul { + fold_array!(mul, { $(self.$field),+ }) + } + + fn is_finite(&self) -> bool where S: Float { + $(self.$field.is_finite())&&+ + } + } + + impl $PointN { + /// Component-wise casting to another type + #[inline] + pub fn cast(&self) -> Option<$PointN> { + $( + let $field = match NumCast::from(self.$field) { + Some(field) => field, + None => return None + }; + )+ + Some($PointN { $($field),+ }) + } + } + + impl MetricSpace for $PointN { + type Metric = S; + + #[inline] + fn distance2(self, other: Self) -> S { + (other - self).magnitude2() + } + } + + impl EuclideanSpace for $PointN { + type Scalar = S; + type Diff = $VectorN; + + #[inline] + fn origin() -> $PointN { + $PointN { $($field: S::zero()),+ } + } + + #[inline] + fn from_vec(v: $VectorN) -> $PointN { + $PointN::new($(v.$field),+) + } + + #[inline] + fn to_vec(self) -> $VectorN { + $VectorN::new($(self.$field),+) + } + + #[inline] + fn dot(self, v: $VectorN) -> S { + $VectorN::new($(self.$field * v.$field),+).sum() + } + } + + impl approx::AbsDiffEq for $PointN { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + S::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) + -> bool + { + $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ + } + } + + impl approx::RelativeEq for $PointN { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ + } + } + + impl approx::UlpsEq for $PointN { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ + } + } + + impl Bounded for $PointN { + #[inline] + fn min_value() -> $PointN { + $PointN { $($field: S::min_value()),+ } + } + + #[inline] + fn max_value() -> $PointN { + $PointN { $($field: S::max_value()),+ } + } + } + + impl_operator!( Add<$VectorN > for $PointN { + fn add(lhs, rhs) -> $PointN { $PointN::new($(lhs.$field + rhs.$field),+) } + }); + impl_operator!( Sub<$VectorN> for $PointN { + fn sub(lhs, rhs) -> $PointN { $PointN::new($(lhs.$field - rhs.$field),+) } + }); + impl_assignment_operator!( AddAssign<$VectorN > for $PointN { + fn add_assign(&mut self, vector) { $(self.$field += vector.$field);+ } + }); + impl_assignment_operator!( SubAssign<$VectorN> for $PointN { + fn sub_assign(&mut self, vector) { $(self.$field -= vector.$field);+ } + }); + + impl_operator!( Sub<$PointN > for $PointN { + fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } + }); + + impl_operator!( Mul for $PointN { + fn mul(point, scalar) -> $PointN { $PointN::new($(point.$field * scalar),+) } + }); + impl_operator!( Div for $PointN { + fn div(point, scalar) -> $PointN { $PointN::new($(point.$field / scalar),+) } + }); + impl_operator!( Rem for $PointN { + fn rem(point, scalar) -> $PointN { $PointN::new($(point.$field % scalar),+) } + }); + impl_assignment_operator!( MulAssign for $PointN { + fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } + }); + impl_assignment_operator!( DivAssign for $PointN { + fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } + }); + impl_assignment_operator!( RemAssign for $PointN { + fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } + }); + + impl ElementWise for $PointN { + #[inline] fn add_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field + rhs.$field),+) } + #[inline] fn sub_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field - rhs.$field),+) } + #[inline] fn mul_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field * rhs.$field),+) } + #[inline] fn div_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field / rhs.$field),+) } + #[inline] fn rem_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field % rhs.$field),+) } + + #[inline] fn add_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field += rhs.$field);+ } + #[inline] fn sub_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field -= rhs.$field);+ } + #[inline] fn mul_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field *= rhs.$field);+ } + #[inline] fn div_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field /= rhs.$field);+ } + #[inline] fn rem_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field %= rhs.$field);+ } + } + + impl ElementWise for $PointN { + #[inline] fn add_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field + rhs),+) } + #[inline] fn sub_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field - rhs),+) } + #[inline] fn mul_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field * rhs),+) } + #[inline] fn div_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field / rhs),+) } + #[inline] fn rem_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field % rhs),+) } + + #[inline] fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } + #[inline] fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } + #[inline] fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } + #[inline] fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } + #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } + } + + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + impl_scalar_ops!($PointN { $($field),+ }); + + impl_index_operators!($PointN, $n, S, usize); + impl_index_operators!($PointN, $n, [S], Range); + impl_index_operators!($PointN, $n, [S], RangeTo); + impl_index_operators!($PointN, $n, [S], RangeFrom); + impl_index_operators!($PointN, $n, [S], RangeFull); + } +} + +macro_rules! impl_scalar_ops { + ($PointN:ident<$S:ident> { $($field:ident),+ }) => { + impl_operator!(Mul<$PointN<$S>> for $S { + fn mul(scalar, point) -> $PointN<$S> { $PointN::new($(scalar * point.$field),+) } + }); + impl_operator!(Div<$PointN<$S>> for $S { + fn div(scalar, point) -> $PointN<$S> { $PointN::new($(scalar / point.$field),+) } + }); + impl_operator!(Rem<$PointN<$S>> for $S { + fn rem(scalar, point) -> $PointN<$S> { $PointN::new($(scalar % point.$field),+) } + }); + }; +} + +impl_point!(Point1 { x }, Vector1, 1, point1); +impl_point!(Point2 { x, y }, Vector2, 2, point2); +impl_point!(Point3 { x, y, z }, Vector3, 3, point3); + +impl Point1 { + impl_swizzle_functions!(Point1, Point2, Point3, S, x); +} + +impl Point2 { + impl_swizzle_functions!(Point1, Point2, Point3, S, xy); +} + +impl Point3 { + impl_swizzle_functions!(Point1, Point2, Point3, S, xyz); +} + +impl_fixed_array_conversions!(Point1 { x: 0 }, 1); +impl_fixed_array_conversions!(Point2 { x: 0, y: 1 }, 2); +impl_fixed_array_conversions!(Point3 { x: 0, y: 1, z: 2 }, 3); + +impl_tuple_conversions!(Point1 { x }, (S,)); +impl_tuple_conversions!(Point2 { x, y }, (S, S)); +impl_tuple_conversions!(Point3 { x, y, z }, (S, S, S)); + +#[cfg(feature = "mint")] +impl_mint_conversions!(Point2 { x, y }, Point2); +#[cfg(feature = "mint")] +impl_mint_conversions!(Point3 { x, y, z }, Point3); + +impl fmt::Debug for Point1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Point1 ")?; + <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Point2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Point2 ")?; + <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Point3 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Point3 ")?; + <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +#[cfg(test)] +mod tests { + mod point2 { + use point::*; + + const POINT2: Point2 = Point2 { x: 1, y: 2 }; + + #[test] + fn test_index() { + assert_eq!(POINT2[0], POINT2.x); + assert_eq!(POINT2[1], POINT2.y); + } + + #[test] + fn test_index_mut() { + let mut p = POINT2; + *&mut p[0] = 0; + assert_eq!(p, [0, 2].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + POINT2[2]; + } + + #[test] + fn test_index_range() { + assert_eq!(&POINT2[..0], &[]); + assert_eq!(&POINT2[..1], &[1]); + assert_eq!(POINT2[..0].len(), 0); + assert_eq!(POINT2[..1].len(), 1); + assert_eq!(&POINT2[2..], &[]); + assert_eq!(&POINT2[1..], &[2]); + assert_eq!(POINT2[2..].len(), 0); + assert_eq!(POINT2[1..].len(), 1); + assert_eq!(&POINT2[..], &[1, 2]); + assert_eq!(POINT2[..].len(), 2); + } + + #[test] + fn test_into() { + let p = POINT2; + { + let p: [i32; 2] = p.into(); + assert_eq!(p, [1, 2]); + } + { + let p: (i32, i32) = p.into(); + assert_eq!(p, (1, 2)); + } + } + + #[test] + fn test_as_ref() { + let p = POINT2; + { + let p: &[i32; 2] = p.as_ref(); + assert_eq!(p, &[1, 2]); + } + { + let p: &(i32, i32) = p.as_ref(); + assert_eq!(p, &(1, 2)); + } + } + + #[test] + fn test_as_mut() { + let mut p = POINT2; + { + let p: &mut [i32; 2] = p.as_mut(); + assert_eq!(p, &mut [1, 2]); + } + { + let p: &mut (i32, i32) = p.as_mut(); + assert_eq!(p, &mut (1, 2)); + } + } + + #[test] + fn test_from() { + assert_eq!(Point2::from([1, 2]), POINT2); + { + let p = &[1, 2]; + let p: &Point2<_> = From::from(p); + assert_eq!(p, &POINT2); + } + { + let p = &mut [1, 2]; + let p: &mut Point2<_> = From::from(p); + assert_eq!(p, &POINT2); + } + assert_eq!(Point2::from((1, 2)), POINT2); + { + let p = &(1, 2); + let p: &Point2<_> = From::from(p); + assert_eq!(p, &POINT2); + } + { + let p = &mut (1, 2); + let p: &mut Point2<_> = From::from(p); + assert_eq!(p, &POINT2); + } + } + + #[test] + fn test_zip() { + assert_eq!( + Point2::new(true, false), + Point2::new(-2, 1).zip(Point2::new(-1, -1), |a, b| a < b) + ); + } + } + + mod point3 { + use point::*; + + const POINT3: Point3 = Point3 { x: 1, y: 2, z: 3 }; + + #[test] + fn test_index() { + assert_eq!(POINT3[0], POINT3.x); + assert_eq!(POINT3[1], POINT3.y); + assert_eq!(POINT3[2], POINT3.z); + } + + #[test] + fn test_index_mut() { + let mut p = POINT3; + *&mut p[1] = 0; + assert_eq!(p, [1, 0, 3].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + POINT3[3]; + } + + #[test] + fn test_index_range() { + assert_eq!(&POINT3[..1], &[1]); + assert_eq!(&POINT3[..2], &[1, 2]); + assert_eq!(POINT3[..1].len(), 1); + assert_eq!(POINT3[..2].len(), 2); + assert_eq!(&POINT3[2..], &[3]); + assert_eq!(&POINT3[1..], &[2, 3]); + assert_eq!(POINT3[2..].len(), 1); + assert_eq!(POINT3[1..].len(), 2); + assert_eq!(&POINT3[..], &[1, 2, 3]); + assert_eq!(POINT3[..].len(), 3); + } + + #[test] + fn test_into() { + let p = POINT3; + { + let p: [i32; 3] = p.into(); + assert_eq!(p, [1, 2, 3]); + } + { + let p: (i32, i32, i32) = p.into(); + assert_eq!(p, (1, 2, 3)); + } + } + + #[test] + fn test_as_ref() { + let p = POINT3; + { + let p: &[i32; 3] = p.as_ref(); + assert_eq!(p, &[1, 2, 3]); + } + { + let p: &(i32, i32, i32) = p.as_ref(); + assert_eq!(p, &(1, 2, 3)); + } + } + + #[test] + fn test_as_mut() { + let mut p = POINT3; + { + let p: &mut [i32; 3] = p.as_mut(); + assert_eq!(p, &mut [1, 2, 3]); + } + { + let p: &mut (i32, i32, i32) = p.as_mut(); + assert_eq!(p, &mut (1, 2, 3)); + } + } + + #[test] + fn test_from() { + assert_eq!(Point3::from([1, 2, 3]), POINT3); + { + let p = &[1, 2, 3]; + let p: &Point3<_> = From::from(p); + assert_eq!(p, &POINT3); + } + { + let p = &mut [1, 2, 3]; + let p: &mut Point3<_> = From::from(p); + assert_eq!(p, &POINT3); + } + assert_eq!(Point3::from((1, 2, 3)), POINT3); + { + let p = &(1, 2, 3); + let p: &Point3<_> = From::from(p); + assert_eq!(p, &POINT3); + } + { + let p = &mut (1, 2, 3); + let p: &mut Point3<_> = From::from(p); + assert_eq!(p, &POINT3); + } + } + + #[test] + fn test_zip() { + assert_eq!( + Point3::new(true, false, false), + Point3::new(-2, 1, 0).zip(Point3::new(-1, -1, -1), |a, b| a < b) + ); + } + } +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/prelude.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/prelude.rs old mode 100755 new mode 100644 similarity index 100% rename from third_party/cargo/vendor/cgmath-0.17.0/src/prelude.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/prelude.rs diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/projection.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/projection.rs old mode 100755 new mode 100644 similarity index 95% rename from third_party/cargo/vendor/cgmath-0.17.0/src/projection.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/projection.rs index 5219ee3..8ba3dc0 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/projection.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/projection.rs @@ -13,8 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use num_traits::Zero; use num_traits::cast; +use num_traits::Zero; use structure::Angle; @@ -38,7 +38,8 @@ pub fn perspective>>( aspect: aspect, near: near, far: far, - }.into() + } + .into() } /// Create a perspective matrix from a view frustum. @@ -54,7 +55,8 @@ pub fn frustum(left: S, right: S, bottom: S, top: S, near: S, far: top: top, near: near, far: far, - }.into() + } + .into() } /// Create an orthographic projection matrix. @@ -70,7 +72,8 @@ pub fn ortho(left: S, right: S, bottom: S, top: S, near: S, far: S top: top, near: near, far: far, - }.into() + } + .into() } /// A perspective projection based on a vertical field-of-view angle. @@ -114,10 +117,11 @@ impl From> for Matrix4 { "The vertical field of view cannot be greater than a half turn, found: {:?}", persp.fovy ); + assert!( - persp.aspect > S::zero(), - "The aspect ratio cannot be below zero, found: {:?}", - persp.aspect + abs_diff_ne!(persp.aspect.abs(), S::zero()), + "The absolute aspect ratio cannot be zero, found: {:?}", + persp.aspect.abs() ); assert!( persp.near > S::zero(), @@ -130,8 +134,8 @@ impl From> for Matrix4 { persp.far ); assert!( - persp.far > persp.near, - "The far plane cannot be closer than the near plane, found: far: {:?}, near: {:?}", + abs_diff_ne!(persp.far, persp.near), + "The far plane and near plane are too close, found: far: {:?}, near: {:?}", persp.far, persp.near ); diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/quaternion.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/quaternion.rs new file mode 100644 index 0000000..06fb637 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/quaternion.rs @@ -0,0 +1,966 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::iter; +use std::mem; +use std::ops::*; + +use num_traits::{cast, NumCast}; +#[cfg(feature = "rand")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use structure::*; + +use angle::Rad; +use approx; +use euler::Euler; +use matrix::{Matrix3, Matrix4}; +use num::BaseFloat; +use point::Point3; +use rotation::{Basis3, Rotation, Rotation3}; +use vector::Vector3; + +#[cfg(feature = "mint")] +use mint; + +/// A [quaternion](https://en.wikipedia.org/wiki/Quaternion) in scalar/vector +/// form. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Quaternion { + /// The vector part of the quaternion. + pub v: Vector3, + /// The scalar part of the quaternion. + pub s: S, +} + +impl Quaternion { + /// Construct a new quaternion from one scalar component and three + /// imaginary components. + #[inline] + pub const fn new(w: S, xi: S, yj: S, zk: S) -> Quaternion { + Quaternion::from_sv(w, Vector3::new(xi, yj, zk)) + } + + /// Construct a new quaternion from a scalar and a vector. + #[inline] + pub const fn from_sv(s: S, v: Vector3) -> Quaternion { + Quaternion { s: s, v: v } + } +} + +impl Quaternion { + /// Construct a new quaternion as a closest arc between two vectors + /// + /// Return the closest rotation that turns `src` vector into `dst`. + /// + /// - [Related StackOverflow question] + /// (http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another) + /// - [Ogre implementation for normalized vectors] + /// (https://bitbucket.org/sinbad/ogre/src/9db75e3ba05c/OgreMain/include/OgreVector3.h?fileviewer=file-view-default#cl-651) + pub fn from_arc( + src: Vector3, + dst: Vector3, + fallback: Option>, + ) -> Quaternion { + let mag_avg = (src.magnitude2() * dst.magnitude2()).sqrt(); + let dot = src.dot(dst); + if ulps_eq!(dot, &mag_avg) { + Quaternion::::one() + } else if ulps_eq!(dot, &-mag_avg) { + let axis = fallback.unwrap_or_else(|| { + let mut v = Vector3::unit_x().cross(src); + if ulps_eq!(v, &Zero::zero()) { + v = Vector3::unit_y().cross(src); + } + v.normalize() + }); + Quaternion::from_axis_angle(axis, Rad::turn_div_2()) + } else { + Quaternion::from_sv(mag_avg + dot, src.cross(dst)).normalize() + } + } + + /// The conjugate of the quaternion. + #[inline] + pub fn conjugate(self) -> Quaternion { + Quaternion::from_sv(self.s, -self.v) + } + + /// Do a normalized linear interpolation with `other`, by `amount`. + /// + /// This takes the shortest path, so if the quaternions have a negative + /// dot product, the interpolation will be between `self` and `-other`. + pub fn nlerp(self, mut other: Quaternion, amount: S) -> Quaternion { + if self.dot(other) < S::zero() { + other = -other; + } + + (self * (S::one() - amount) + other * amount).normalize() + } + + /// Spherical Linear Interpolation + /// + /// Return the spherical linear interpolation between the quaternion and + /// `other`. Both quaternions should be normalized first. + /// + /// This takes the shortest path, so if the quaternions have a negative + /// dot product, the interpolation will be between `self` and `-other`. + /// + /// # Performance notes + /// + /// The `acos` operation used in `slerp` is an expensive operation, so + /// unless your quaternions are far away from each other it's generally + /// more advisable to use `nlerp` when you know your rotations are going + /// to be small. + /// + /// - [Understanding Slerp, Then Not Using It] + /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/) + /// - [Arcsynthesis OpenGL tutorial] + /// (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html) + pub fn slerp(self, mut other: Quaternion, amount: S) -> Quaternion { + let mut dot = self.dot(other); + let dot_threshold: S = cast(0.9995f64).unwrap(); + + if dot < S::zero() { + other = -other; + dot = -dot; + } + + // if quaternions are close together use `nlerp` + if dot > dot_threshold { + self.nlerp(other, amount) + } else { + // stay within the domain of acos() + let robust_dot = dot.min(S::one()).max(-S::one()); + + let theta = Rad::acos(robust_dot); + + let scale1 = Rad::sin(theta * (S::one() - amount)); + let scale2 = Rad::sin(theta * amount); + + (self * scale1 + other * scale2).normalize() + } + } + + pub fn is_finite(&self) -> bool { + self.s.is_finite() && self.v.is_finite() + } +} + +impl Zero for Quaternion { + #[inline] + fn zero() -> Quaternion { + Quaternion::from_sv(S::zero(), Vector3::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + ulps_eq!(self, &Quaternion::::zero()) + } +} + +impl One for Quaternion { + #[inline] + fn one() -> Quaternion { + Quaternion::from_sv(S::one(), Vector3::zero()) + } +} + +impl iter::Sum> for Quaternion { + #[inline] + fn sum>>(iter: I) -> Quaternion { + iter.fold(Quaternion::::zero(), Add::add) + } +} + +impl<'a, S: 'a + BaseFloat> iter::Sum<&'a Quaternion> for Quaternion { + #[inline] + fn sum>>(iter: I) -> Quaternion { + iter.fold(Quaternion::::zero(), Add::add) + } +} + +impl iter::Product> for Quaternion { + #[inline] + fn product>>(iter: I) -> Quaternion { + iter.fold(Quaternion::::one(), Mul::mul) + } +} + +impl<'a, S: 'a + BaseFloat> iter::Product<&'a Quaternion> for Quaternion { + #[inline] + fn product>>(iter: I) -> Quaternion { + iter.fold(Quaternion::::one(), Mul::mul) + } +} + +impl VectorSpace for Quaternion { + type Scalar = S; +} + +impl MetricSpace for Quaternion { + type Metric = S; + + #[inline] + fn distance2(self, other: Self) -> S { + (other - self).magnitude2() + } +} + +impl Quaternion { + /// Component-wise casting to another type. + pub fn cast(&self) -> Option> { + let s = match NumCast::from(self.s) { + Some(s) => s, + None => return None, + }; + let v = match self.v.cast() { + Some(v) => v, + None => return None, + }; + Some(Quaternion::from_sv(s, v)) + } +} + +impl InnerSpace for Quaternion { + #[inline] + default_fn!( dot(self, other: Quaternion) -> S { + self.s * other.s + self.v.dot(other.v) + } ); +} + +impl From> for Quaternion +where + A: Angle + Into::Unitless>>, +{ + fn from(src: Euler) -> Quaternion { + // Euclidean Space has an Euler to quat equation, but it is for a different order (YXZ): + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm + // Page A-2 here has the formula for XYZ: + // http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf + + let half = cast(0.5f64).unwrap(); + let (s_x, c_x) = Rad::sin_cos(src.x.into() * half); + let (s_y, c_y) = Rad::sin_cos(src.y.into() * half); + let (s_z, c_z) = Rad::sin_cos(src.z.into() * half); + + Quaternion::new( + -s_x * s_y * s_z + c_x * c_y * c_z, + s_x * c_y * c_z + s_y * s_z * c_x, + -s_x * s_z * c_y + s_y * c_x * c_z, + s_x * s_y * c_z + s_z * c_x * c_y, + ) + } +} + +impl_operator!( Neg for Quaternion { + fn neg(quat) -> Quaternion { + Quaternion::from_sv(-quat.s, -quat.v) + } +}); + +impl_operator!( Mul for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) + } +}); + +impl_assignment_operator!( MulAssign for Quaternion { + fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } +}); + +impl_operator!( Div for Quaternion { + fn div(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) + } +}); + +impl_assignment_operator!( DivAssign for Quaternion { + fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } +}); + +impl_operator!( Rem for Quaternion { + fn rem(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s % rhs, lhs.v % rhs) + } +}); + +impl_assignment_operator!( RemAssign for Quaternion { + fn rem_assign(&mut self, scalar) { self.s %= scalar; self.v %= scalar; } +}); + +impl_operator!( Mul > for Quaternion { + fn mul(lhs, rhs) -> Vector3 {{ + let rhs = rhs.clone(); + let two: S = cast(2i8).unwrap(); + let tmp = lhs.v.cross(rhs) + (rhs * lhs.s); + (lhs.v.cross(tmp) * two) + rhs + }} +}); + +impl_operator!( Add > for Quaternion { + fn add(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) + } +}); + +impl_assignment_operator!( AddAssign > for Quaternion { + fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } +}); + +impl_operator!( Sub > for Quaternion { + fn sub(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) + } +}); + +impl_assignment_operator!( SubAssign > for Quaternion { + fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } +}); + +impl_operator!( Mul > for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + Quaternion::new( + lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, + lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, + lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, + lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x, + ) + } +}); + +macro_rules! impl_scalar_mul { + ($S:ident) => { + impl_operator!(Mul> for $S { + fn mul(scalar, quat) -> Quaternion<$S> { + Quaternion::from_sv(scalar * quat.s, scalar * quat.v) + } + }); + }; +} + +macro_rules! impl_scalar_div { + ($S:ident) => { + impl_operator!(Div> for $S { + fn div(scalar, quat) -> Quaternion<$S> { + Quaternion::from_sv(scalar / quat.s, scalar / quat.v) + } + }); + }; +} + +impl_scalar_mul!(f32); +impl_scalar_mul!(f64); +impl_scalar_div!(f32); +impl_scalar_div!(f64); + +impl approx::AbsDiffEq for Quaternion { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + S::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + S::abs_diff_eq(&self.s, &other.s, epsilon) + && Vector3::abs_diff_eq(&self.v, &other.v, epsilon) + } +} + +impl approx::RelativeEq for Quaternion { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + S::relative_eq(&self.s, &other.s, epsilon, max_relative) + && Vector3::relative_eq(&self.v, &other.v, epsilon, max_relative) + } +} + +impl approx::UlpsEq for Quaternion { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + S::ulps_eq(&self.s, &other.s, epsilon, max_ulps) + && Vector3::ulps_eq(&self.v, &other.v, epsilon, max_ulps) + } +} + +impl From> for Matrix3 { + /// Convert the quaternion to a 3 x 3 rotation matrix. + fn from(quat: Quaternion) -> Matrix3 { + let x2 = quat.v.x + quat.v.x; + let y2 = quat.v.y + quat.v.y; + let z2 = quat.v.z + quat.v.z; + + let xx2 = x2 * quat.v.x; + let xy2 = x2 * quat.v.y; + let xz2 = x2 * quat.v.z; + + let yy2 = y2 * quat.v.y; + let yz2 = y2 * quat.v.z; + let zz2 = z2 * quat.v.z; + + let sy2 = y2 * quat.s; + let sz2 = z2 * quat.s; + let sx2 = x2 * quat.s; + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix3::new( + S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, + xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, + xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2, + ) + } +} + +impl From> for Matrix4 { + /// Convert the quaternion to a 4 x 4 rotation matrix. + fn from(quat: Quaternion) -> Matrix4 { + let x2 = quat.v.x + quat.v.x; + let y2 = quat.v.y + quat.v.y; + let z2 = quat.v.z + quat.v.z; + + let xx2 = x2 * quat.v.x; + let xy2 = x2 * quat.v.y; + let xz2 = x2 * quat.v.z; + + let yy2 = y2 * quat.v.y; + let yz2 = y2 * quat.v.z; + let zz2 = z2 * quat.v.z; + + let sy2 = y2 * quat.s; + let sz2 = z2 * quat.s; + let sx2 = x2 * quat.s; + + #[cfg_attr(rustfmt, rustfmt_skip)] + Matrix4::new( + S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, S::zero(), + xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, S::zero(), + xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2, S::zero(), + S::zero(), S::zero(), S::zero(), S::one(), + ) + } +} + +// Quaternion Rotation impls + +impl From> for Basis3 { + #[inline] + fn from(quat: Quaternion) -> Basis3 { + Basis3::from_quaternion(&quat) + } +} + +impl Rotation for Quaternion { + type Space = Point3; + + #[inline] + fn look_at(dir: Vector3, up: Vector3) -> Quaternion { + Matrix3::look_to_lh(dir, up).into() + } + + #[inline] + fn between_vectors(a: Vector3, b: Vector3) -> Quaternion { + // http://stackoverflow.com/a/11741520/2074937 see 'Half-Way Quaternion Solution' + + let k_cos_theta = a.dot(b); + + // same direction + if ulps_eq!(k_cos_theta, S::one()) { + return Quaternion::::one(); + } + + let k = (a.magnitude2() * b.magnitude2()).sqrt(); + + // opposite direction + if ulps_eq!(k_cos_theta / k, -S::one()) { + let mut orthogonal = a.cross(Vector3::unit_x()); + if ulps_eq!(orthogonal.magnitude2(), S::zero()) { + orthogonal = a.cross(Vector3::unit_y()); + } + return Quaternion::from_sv(S::zero(), orthogonal.normalize()); + } + + // any other direction + Quaternion::from_sv(k + k_cos_theta, a.cross(b)).normalize() + } + + /// Evaluate the conjugation of `vec` by `self`. + /// + /// Note that `self` should be a unit quaternion (i.e. normalized) to represent a 3D rotation. + #[inline] + fn rotate_vector(&self, vec: Vector3) -> Vector3 { + self * vec + } + + #[inline] + fn invert(&self) -> Quaternion { + self.conjugate() / self.magnitude2() + } +} + +impl Rotation3 for Quaternion { + type Scalar = S; + + #[inline] + fn from_axis_angle>>(axis: Vector3, angle: A) -> Quaternion { + let (s, c) = Rad::sin_cos(angle.into() * cast(0.5f64).unwrap()); + Quaternion::from_sv(c, axis * s) + } +} + +impl Into<[S; 4]> for Quaternion { + #[inline] + fn into(self) -> [S; 4] { + match self.into() { + (xi, yj, zk, w) => [xi, yj, zk, w], + } + } +} + +impl AsRef<[S; 4]> for Quaternion { + #[inline] + fn as_ref(&self) -> &[S; 4] { + unsafe { mem::transmute(self) } + } +} + +impl AsMut<[S; 4]> for Quaternion { + #[inline] + fn as_mut(&mut self) -> &mut [S; 4] { + unsafe { mem::transmute(self) } + } +} + +impl From<[S; 4]> for Quaternion { + #[inline] + fn from(v: [S; 4]) -> Quaternion { + Quaternion::new(v[3], v[0], v[1], v[2]) + } +} + +impl<'a, S: BaseFloat> From<&'a [S; 4]> for &'a Quaternion { + #[inline] + fn from(v: &'a [S; 4]) -> &'a Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl<'a, S: BaseFloat> From<&'a mut [S; 4]> for &'a mut Quaternion { + #[inline] + fn from(v: &'a mut [S; 4]) -> &'a mut Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl Into<(S, S, S, S)> for Quaternion { + #[inline] + fn into(self) -> (S, S, S, S) { + match self { + Quaternion { + s, + v: Vector3 { x, y, z }, + } => (x, y, z, s), + } + } +} + +impl AsRef<(S, S, S, S)> for Quaternion { + #[inline] + fn as_ref(&self) -> &(S, S, S, S) { + unsafe { mem::transmute(self) } + } +} + +impl AsMut<(S, S, S, S)> for Quaternion { + #[inline] + fn as_mut(&mut self) -> &mut (S, S, S, S) { + unsafe { mem::transmute(self) } + } +} + +impl From<(S, S, S, S)> for Quaternion { + #[inline] + fn from(v: (S, S, S, S)) -> Quaternion { + match v { + (xi, yj, zk, w) => Quaternion::new(w, xi, yj, zk), + } + } +} + +impl<'a, S: BaseFloat> From<&'a (S, S, S, S)> for &'a Quaternion { + #[inline] + fn from(v: &'a (S, S, S, S)) -> &'a Quaternion { + unsafe { mem::transmute(v) } + } +} + +impl<'a, S: BaseFloat> From<&'a mut (S, S, S, S)> for &'a mut Quaternion { + #[inline] + fn from(v: &'a mut (S, S, S, S)) -> &'a mut Quaternion { + unsafe { mem::transmute(v) } + } +} + +macro_rules! index_operators { + ($S:ident, $Output:ty, $I:ty) => { + impl<$S: BaseFloat> Index<$I> for Quaternion<$S> { + type Output = $Output; + + #[inline] + fn index<'a>(&'a self, i: $I) -> &'a $Output { + let v: &[$S; 4] = self.as_ref(); + &v[i] + } + } + + impl<$S: BaseFloat> IndexMut<$I> for Quaternion<$S> { + #[inline] + fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { + let v: &mut [$S; 4] = self.as_mut(); + &mut v[i] + } + } + }; +} + +index_operators!(S, S, usize); +index_operators!(S, [S], Range); +index_operators!(S, [S], RangeTo); +index_operators!(S, [S], RangeFrom); +index_operators!(S, [S], RangeFull); + +#[cfg(feature = "rand")] +impl Distribution> for Standard +where + Standard: Distribution, + Standard: Distribution>, + S: BaseFloat, +{ + #[inline] + fn sample(&self, rng: &mut R) -> Quaternion { + Quaternion::from_sv(rng.gen(), rng.gen()) + } +} + +#[cfg(feature = "mint")] +impl From> for Quaternion { + fn from(q: mint::Quaternion) -> Self { + Quaternion { + s: q.s, + v: q.v.into(), + } + } +} + +#[cfg(feature = "mint")] +impl Into> for Quaternion { + fn into(self) -> mint::Quaternion { + mint::Quaternion { + s: self.s, + v: self.v.into(), + } + } +} + +#[cfg(test)] +mod tests { + use quaternion::*; + use vector::*; + + const QUATERNION: Quaternion = Quaternion { + v: Vector3 { + x: 1.0, + y: 2.0, + z: 3.0, + }, + s: 4.0, + }; + + #[test] + fn test_into() { + let v = QUATERNION; + { + let v: [f32; 4] = v.into(); + assert_eq!(v, [1.0, 2.0, 3.0, 4.0]); + } + { + let v: (f32, f32, f32, f32) = v.into(); + assert_eq!(v, (1.0, 2.0, 3.0, 4.0)); + } + } + + #[test] + fn test_as_ref() { + let v = QUATERNION; + { + let v: &[f32; 4] = v.as_ref(); + assert_eq!(v, &[1.0, 2.0, 3.0, 4.0]); + } + { + let v: &(f32, f32, f32, f32) = v.as_ref(); + assert_eq!(v, &(1.0, 2.0, 3.0, 4.0)); + } + } + + #[test] + fn test_as_mut() { + let mut v = QUATERNION; + { + let v: &mut [f32; 4] = v.as_mut(); + assert_eq!(v, &mut [1.0, 2.0, 3.0, 4.0]); + } + { + let v: &mut (f32, f32, f32, f32) = v.as_mut(); + assert_eq!(v, &mut (1.0, 2.0, 3.0, 4.0)); + } + } + + #[test] + fn test_from() { + assert_eq!(Quaternion::from([1.0, 2.0, 3.0, 4.0]), QUATERNION); + { + let v = &[1.0, 2.0, 3.0, 4.0]; + let v: &Quaternion<_> = From::from(v); + assert_eq!(v, &QUATERNION); + } + { + let v = &mut [1.0, 2.0, 3.0, 4.0]; + let v: &mut Quaternion<_> = From::from(v); + assert_eq!(v, &QUATERNION); + } + assert_eq!(Quaternion::from((1.0, 2.0, 3.0, 4.0)), QUATERNION); + { + let v = &(1.0, 2.0, 3.0, 4.0); + let v: &Quaternion<_> = From::from(v); + assert_eq!(v, &QUATERNION); + } + { + let v = &mut (1.0, 2.0, 3.0, 4.0); + let v: &mut Quaternion<_> = From::from(v); + assert_eq!(v, &QUATERNION); + } + } + + #[test] + fn test_nlerp_same() { + let q = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + assert_ulps_eq!(q, q.nlerp(q, 0.1234)); + } + + #[test] + fn test_nlerp_start() { + let q = Quaternion::from([0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + assert_ulps_eq!(q, q.nlerp(r, 0.0)); + } + + #[test] + fn test_nlerp_end() { + let q = Quaternion::from([0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + assert_ulps_eq!(r, q.nlerp(r, 1.0)); + } + + #[test] + fn test_nlerp_half() { + let q = Quaternion::from([-0.5, 0.5, 0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = + Quaternion::from([0.0, 1.0 / 3f64.sqrt(), 1.0 / 3f64.sqrt(), 1.0 / 3f64.sqrt()]); + assert_ulps_eq!(expected, q.nlerp(r, 0.5)); + } + + #[test] + fn test_nlerp_quarter() { + let q = Quaternion::from([-0.5, 0.5, 0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -1.0 / 13f64.sqrt(), + 2.0 / 13f64.sqrt(), + 2.0 / 13f64.sqrt(), + 2.0 / 13f64.sqrt(), + ]); + assert_ulps_eq!(expected, q.nlerp(r, 0.25)); + } + + #[test] + fn test_nlerp_zero_dot() { + let q = Quaternion::from([-0.5, -0.5, 0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -1.0 / 10f64.sqrt(), + -1.0 / 10f64.sqrt(), + 2.0 / 10f64.sqrt(), + 2.0 / 10f64.sqrt(), + ]); + assert_ulps_eq!(expected, q.nlerp(r, 0.25)); + } + + #[test] + fn test_nlerp_negative_dot() { + let q = Quaternion::from([-0.5, -0.5, -0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -2.0 / 13f64.sqrt(), + -2.0 / 13f64.sqrt(), + -2.0 / 13f64.sqrt(), + 1.0 / 13f64.sqrt(), + ]); + assert_ulps_eq!(expected, q.nlerp(r, 0.25)); + } + + #[test] + fn test_nlerp_opposite() { + let q = Quaternion::from([-0.5, -0.5, -0.5, -0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + assert_ulps_eq!(q, q.nlerp(r, 0.25)); + assert_ulps_eq!(q, q.nlerp(r, 0.75)); + } + + #[test] + fn test_nlerp_extrapolate() { + let q = Quaternion::from([-0.5, -0.5, -0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -1.0 / 12f64.sqrt(), + -1.0 / 12f64.sqrt(), + -1.0 / 12f64.sqrt(), + 3.0 / 12f64.sqrt(), + ]); + assert_ulps_eq!(expected, q.nlerp(r, -1.0)); + } + + #[test] + fn test_slerp_same() { + let q = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + assert_ulps_eq!(q, q.slerp(q, 0.1234)); + } + + #[test] + fn test_slerp_start() { + let q = Quaternion::from([0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + assert_ulps_eq!(q, q.slerp(r, 0.0)); + } + + #[test] + fn test_slerp_end() { + let q = Quaternion::from([0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + assert_ulps_eq!(r, q.slerp(r, 1.0)); + } + + #[test] + fn test_slerp_half() { + let q = Quaternion::from([-0.5, 0.5, 0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = + Quaternion::from([0.0, 1.0 / 3f64.sqrt(), 1.0 / 3f64.sqrt(), 1.0 / 3f64.sqrt()]); + assert_ulps_eq!(expected, q.slerp(r, 0.5)); + } + + #[test] + fn test_slerp_quarter() { + let q = Quaternion::from([-0.5, 0.5, 0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -0.2588190451025208, + 0.5576775358252053, + 0.5576775358252053, + 0.5576775358252053, + ]); + assert_ulps_eq!(expected, q.slerp(r, 0.25)); + } + + #[test] + fn test_slerp_zero_dot() { + let q = Quaternion::from([-0.5, -0.5, 0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -0.27059805007309845, + -0.27059805007309845, + 0.6532814824381883, + 0.6532814824381883, + ]); + assert_ulps_eq!(expected, q.slerp(r, 0.25)); + } + + #[test] + fn test_slerp_negative_dot() { + let q = Quaternion::from([-0.5, -0.5, -0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([ + -0.5576775358252053, + -0.5576775358252053, + -0.5576775358252053, + 0.2588190451025208 + ]); + assert_ulps_eq!(expected, q.slerp(r, 0.25)); + } + + #[test] + fn test_slerp_opposite() { + let q = Quaternion::from([-0.5, -0.5, -0.5, -0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + assert_ulps_eq!(q, q.slerp(r, 0.25)); + assert_ulps_eq!(q, q.slerp(r, 0.75)); + } + + #[test] + fn test_slerp_extrapolate() { + let q = Quaternion::from([-0.5, -0.5, -0.5, 0.5]); + let r = Quaternion::from([0.5, 0.5, 0.5, 0.5]); + + let expected = Quaternion::from([0.0, 0.0, 0.0, 1.0]); + assert_ulps_eq!(expected, q.slerp(r, -1.0)); + } + + #[test] + fn test_slerp_regression() { + let a = Quaternion::::new(0.00052311074, 0.9999999, 0.00014682197, -0.000016342687); + let b = Quaternion::::new(0.019973433, -0.99980056, -0.00015678025, 0.000013882192); + + assert_ulps_eq!(a.slerp(b, 0.5).magnitude(), 1.0); + } +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/quaternion_simd.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/quaternion_simd.rs new file mode 100644 index 0000000..bb88056 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/quaternion_simd.rs @@ -0,0 +1,149 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use quaternion::*; + +use structure::*; + +use std::mem; +use std::ops::*; + +use simd::f32x4 as Simdf32x4; + +impl From for Quaternion { + #[inline] + fn from(f: Simdf32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [f32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Into for Quaternion { + #[inline] + fn into(self) -> Simdf32x4 { + let self_ref: &[f32; 4] = self.as_ref(); + Simdf32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl InnerSpace for Quaternion { + #[inline] + fn dot(self, other: Quaternion) -> f32 { + let lhs: Simdf32x4 = self.into(); + let rhs: Simdf32x4 = other.into(); + let r = lhs * rhs; + r.extract(0) + r.extract(1) + r.extract(2) + r.extract(3) + } +} + +impl_operator_simd! { + [Simdf32x4]; Neg for Quaternion { + fn neg(lhs) -> Quaternion { + (-lhs).into() + } + } +} + +impl_operator_simd! {@rs + [Simdf32x4]; Mul for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + (lhs * rhs).into() + } + } +} + +impl MulAssign for Quaternion { + fn mul_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s * other).into(); + } +} + +impl_operator_simd! {@rs + [Simdf32x4]; Div for Quaternion { + fn div(lhs, rhs) -> Quaternion { + (lhs / rhs).into() + } + } +} + +impl DivAssign for Quaternion { + fn div_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s / other).into(); + } +} + +impl_operator_simd! { + [Simdf32x4]; Add> for Quaternion { + fn add(lhs, rhs) -> Quaternion { + (lhs + rhs).into() + } + } +} + +impl AddAssign for Quaternion { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl_operator_simd! { + [Simdf32x4]; Sub> for Quaternion { + fn sub(lhs, rhs) -> Quaternion { + (lhs - rhs).into() + } + } +} + +impl SubAssign for Quaternion { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl_operator_simd! { + [Simdf32x4]; Mul> for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + { + let p0 = Simdf32x4::splat(lhs.extract(0)) * rhs; + let p1 = Simdf32x4::splat(lhs.extract(1)) * Simdf32x4::new( + -rhs.extract(1), rhs.extract(0), -rhs.extract(3), rhs.extract(2) + ); + let p2 = Simdf32x4::splat(lhs.extract(2)) * Simdf32x4::new( + -rhs.extract(2), rhs.extract(3), rhs.extract(0), -rhs.extract(1) + ); + let p3 = Simdf32x4::splat(lhs.extract(3)) * Simdf32x4::new( + -rhs.extract(3), -rhs.extract(2), rhs.extract(1), rhs.extract(0) + ); + (p0 + p1 + p2 + p3).into() + } + } + } +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/rotation.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/rotation.rs new file mode 100644 index 0000000..1e801b6 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/rotation.rs @@ -0,0 +1,489 @@ +// Copyright 2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt; +use std::iter; +use std::ops::*; + +use structure::*; + +use angle::Rad; +use approx; +use euler::Euler; +use matrix::{Matrix2, Matrix3}; +use num::BaseFloat; +use point::{Point2, Point3}; +use quaternion::Quaternion; +use vector::{Vector2, Vector3}; + +/// A trait for a generic rotation. A rotation is a transformation that +/// creates a circular motion, and preserves at least one point in the space. +pub trait Rotation: Sized + Copy + One +where + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: approx::AbsDiffEq::Space as EuclideanSpace>::Scalar>, + Self: approx::RelativeEq::Space as EuclideanSpace>::Scalar>, + Self: approx::UlpsEq::Space as EuclideanSpace>::Scalar>, + ::Scalar: BaseFloat, + Self: iter::Product, +{ + type Space: EuclideanSpace; + + /// Create a rotation to a given direction with an 'up' vector. + fn look_at( + dir: ::Diff, + up: ::Diff, + ) -> Self; + + /// Create a shortest rotation to transform vector 'a' into 'b'. + /// Both given vectors are assumed to have unit length. + fn between_vectors( + a: ::Diff, + b: ::Diff, + ) -> Self; + + /// Rotate a vector using this rotation. + fn rotate_vector( + &self, + vec: ::Diff, + ) -> ::Diff; + + /// Rotate a point using this rotation, by converting it to its + /// representation as a vector. + #[inline] + fn rotate_point(&self, point: Self::Space) -> Self::Space { + Self::Space::from_vec(self.rotate_vector(point.to_vec())) + } + + /// Create a new rotation which "un-does" this rotation. That is, + /// `r * r.invert()` is the identity. + fn invert(&self) -> Self; +} + +/// A two-dimensional rotation. +pub trait Rotation2: + Rotation::Scalar>> + + Into::Scalar>> + + Into::Scalar>> +{ + type Scalar: BaseFloat; + + /// Create a rotation by a given angle. Thus is a redundant case of both + /// from_axis_angle() and from_euler() for 2D space. + fn from_angle>>(theta: A) -> Self; +} + +/// A three-dimensional rotation. +pub trait Rotation3: + Rotation::Scalar>> + + Into::Scalar>> + + Into::Scalar>> + + Into::Scalar>> + + From::Scalar>>> +{ + type Scalar: BaseFloat; + + /// Create a rotation using an angle around a given axis. + /// + /// The specified axis **must be normalized**, or it represents an invalid rotation. + fn from_axis_angle>>(axis: Vector3, angle: A) -> Self; + + /// Create a rotation from an angle around the `x` axis (pitch). + #[inline] + fn from_angle_x>>(theta: A) -> Self { + Rotation3::from_axis_angle(Vector3::unit_x(), theta) + } + + /// Create a rotation from an angle around the `y` axis (yaw). + #[inline] + fn from_angle_y>>(theta: A) -> Self { + Rotation3::from_axis_angle(Vector3::unit_y(), theta) + } + + /// Create a rotation from an angle around the `z` axis (roll). + #[inline] + fn from_angle_z>>(theta: A) -> Self { + Rotation3::from_axis_angle(Vector3::unit_z(), theta) + } +} + +/// A two-dimensional rotation matrix. +/// +/// The matrix is guaranteed to be orthogonal, so some operations can be +/// implemented more efficiently than the implementations for `math::Matrix2`. To +/// enforce orthogonality at the type level the operations have been restricted +/// to a subset of those implemented on `Matrix2`. +/// +/// ## Example +/// +/// Suppose we want to rotate a vector that lies in the x-y plane by some +/// angle. We can accomplish this quite easily with a two-dimensional rotation +/// matrix: +/// +/// ```no_run +/// use cgmath::Rad; +/// use cgmath::Vector2; +/// use cgmath::{Matrix, Matrix2}; +/// use cgmath::{Rotation, Rotation2, Basis2}; +/// use cgmath::UlpsEq; +/// use std::f64; +/// +/// // For simplicity, we will rotate the unit x vector to the unit y vector -- +/// // so the angle is 90 degrees, or π/2. +/// let unit_x: Vector2 = Vector2::unit_x(); +/// let rot: Basis2 = Rotation2::from_angle(Rad(0.5f64 * f64::consts::PI)); +/// +/// // Rotate the vector using the two-dimensional rotation matrix: +/// let unit_y = rot.rotate_vector(unit_x); +/// +/// // Since sin(π/2) may not be exactly zero due to rounding errors, we can +/// // use approx's assert_ulps_eq!() feature to show that it is close enough. +/// // assert_ulps_eq!(&unit_y, &Vector2::unit_y()); // TODO: Figure out how to use this +/// +/// // This is exactly equivalent to using the raw matrix itself: +/// let unit_y2: Matrix2<_> = rot.into(); +/// let unit_y2 = unit_y2 * unit_x; +/// assert_eq!(unit_y2, unit_y); +/// +/// // Note that we can also concatenate rotations: +/// let rot_half: Basis2 = Rotation2::from_angle(Rad(0.25f64 * f64::consts::PI)); +/// let unit_y3 = (rot_half * rot_half).rotate_vector(unit_x); +/// // assert_ulps_eq!(&unit_y3, &unit_y2); // TODO: Figure out how to use this +/// ``` +#[derive(PartialEq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Basis2 { + mat: Matrix2, +} + +impl Basis2 { + pub fn look_at_stable(dir: Vector2, flip: bool) -> Basis2 { + Basis2 { + mat: Matrix2::look_at_stable(dir, flip), + } + } +} + +impl AsRef> for Basis2 { + #[inline] + fn as_ref(&self) -> &Matrix2 { + &self.mat + } +} + +impl From> for Matrix2 { + #[inline] + fn from(b: Basis2) -> Matrix2 { + b.mat + } +} + +impl iter::Product> for Basis2 { + #[inline] + fn product>>(iter: I) -> Basis2 { + iter.fold(Basis2::one(), Mul::mul) + } +} + +impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2> for Basis2 { + #[inline] + fn product>>(iter: I) -> Basis2 { + iter.fold(Basis2::one(), Mul::mul) + } +} + +impl Rotation for Basis2 { + type Space = Point2; + + #[inline] + fn look_at(dir: Vector2, up: Vector2) -> Basis2 { + Basis2 { + mat: Matrix2::look_at(dir, up), + } + } + + #[inline] + fn between_vectors(a: Vector2, b: Vector2) -> Basis2 { + Rotation2::from_angle(Rad::acos(a.dot(b))) + } + + #[inline] + fn rotate_vector(&self, vec: Vector2) -> Vector2 { + self.mat * vec + } + + // TODO: we know the matrix is orthogonal, so this could be re-written + // to be faster + #[inline] + fn invert(&self) -> Basis2 { + Basis2 { + mat: self.mat.invert().unwrap(), + } + } +} + +impl One for Basis2 { + #[inline] + fn one() -> Basis2 { + Basis2 { + mat: Matrix2::one(), + } + } +} + +impl_operator!( Mul > for Basis2 { + fn mul(lhs, rhs) -> Basis2 { Basis2 { mat: lhs.mat * rhs.mat } } +}); + +impl approx::AbsDiffEq for Basis2 { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + S::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + Matrix2::abs_diff_eq(&self.mat, &other.mat, epsilon) + } +} + +impl approx::RelativeEq for Basis2 { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + Matrix2::relative_eq(&self.mat, &other.mat, epsilon, max_relative) + } +} + +impl approx::UlpsEq for Basis2 { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + Matrix2::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps) + } +} + +impl Rotation2 for Basis2 { + type Scalar = S; + + fn from_angle>>(theta: A) -> Basis2 { + Basis2 { + mat: Matrix2::from_angle(theta), + } + } +} + +impl fmt::Debug for Basis2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Basis2 ")?; + <[[S; 2]; 2] as fmt::Debug>::fmt(self.mat.as_ref(), f) + } +} + +/// A three-dimensional rotation matrix. +/// +/// The matrix is guaranteed to be orthogonal, so some operations, specifically +/// inversion, can be implemented more efficiently than the implementations for +/// `math::Matrix3`. To ensure orthogonality is maintained, the operations have +/// been restricted to a subset of those implemented on `Matrix3`. +#[derive(PartialEq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Basis3 { + mat: Matrix3, +} + +impl Basis3 { + /// Create a new rotation matrix from a quaternion. + #[inline] + pub fn from_quaternion(quaternion: &Quaternion) -> Basis3 { + Basis3 { + mat: quaternion.clone().into(), + } + } +} + +impl AsRef> for Basis3 { + #[inline] + fn as_ref(&self) -> &Matrix3 { + &self.mat + } +} + +impl From> for Matrix3 { + #[inline] + fn from(b: Basis3) -> Matrix3 { + b.mat + } +} + +impl From> for Quaternion { + #[inline] + fn from(b: Basis3) -> Quaternion { + b.mat.into() + } +} + +impl iter::Product> for Basis3 { + #[inline] + fn product>>(iter: I) -> Basis3 { + iter.fold(Basis3::one(), Mul::mul) + } +} + +impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3> for Basis3 { + #[inline] + fn product>>(iter: I) -> Basis3 { + iter.fold(Basis3::one(), Mul::mul) + } +} + +impl Rotation for Basis3 { + type Space = Point3; + + #[inline] + fn look_at(dir: Vector3, up: Vector3) -> Basis3 { + Basis3 { + mat: Matrix3::look_to_lh(dir, up), + } + } + + #[inline] + fn between_vectors(a: Vector3, b: Vector3) -> Basis3 { + let q: Quaternion = Rotation::between_vectors(a, b); + q.into() + } + + #[inline] + fn rotate_vector(&self, vec: Vector3) -> Vector3 { + self.mat * vec + } + + // TODO: we know the matrix is orthogonal, so this could be re-written + // to be faster + #[inline] + fn invert(&self) -> Basis3 { + Basis3 { + mat: self.mat.invert().unwrap(), + } + } +} + +impl One for Basis3 { + #[inline] + fn one() -> Basis3 { + Basis3 { + mat: Matrix3::one(), + } + } +} + +impl_operator!( Mul > for Basis3 { + fn mul(lhs, rhs) -> Basis3 { Basis3 { mat: lhs.mat * rhs.mat } } +}); + +impl approx::AbsDiffEq for Basis3 { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + S::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + Matrix3::abs_diff_eq(&self.mat, &other.mat, epsilon) + } +} + +impl approx::RelativeEq for Basis3 { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + Matrix3::relative_eq(&self.mat, &other.mat, epsilon, max_relative) + } +} + +impl approx::UlpsEq for Basis3 { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + Matrix3::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps) + } +} + +impl Rotation3 for Basis3 { + type Scalar = S; + + fn from_axis_angle>>(axis: Vector3, angle: A) -> Basis3 { + Basis3 { + mat: Matrix3::from_axis_angle(axis, angle), + } + } + + fn from_angle_x>>(theta: A) -> Basis3 { + Basis3 { + mat: Matrix3::from_angle_x(theta), + } + } + + fn from_angle_y>>(theta: A) -> Basis3 { + Basis3 { + mat: Matrix3::from_angle_y(theta), + } + } + + fn from_angle_z>>(theta: A) -> Basis3 { + Basis3 { + mat: Matrix3::from_angle_z(theta), + } + } +} + +impl From> for Basis3 +where + A: Into::Unitless>>, +{ + /// Create a three-dimensional rotation matrix from a set of euler angles. + fn from(src: Euler) -> Basis3 { + Basis3 { + mat: Matrix3::from(src), + } + } +} + +impl fmt::Debug for Basis3 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Basis3 ")?; + <[[S; 3]; 3] as fmt::Debug>::fmt(self.mat.as_ref(), f) + } +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/structure.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/structure.rs old mode 100755 new mode 100644 similarity index 95% rename from third_party/cargo/vendor/cgmath-0.17.0/src/structure.rs rename to third_party/cargo/vendor/cgmath-0.18.0/src/structure.rs index 8721e51..9fe7928 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/structure.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/structure.rs @@ -91,7 +91,7 @@ where /// Whether all elements of the array are finite fn is_finite(&self) -> bool where - Self::Element: BaseFloat; + Self::Element: Float; } /// Element-wise arithmetic operations. These are supplied for pragmatic @@ -195,7 +195,7 @@ where /// Examples are vectors, points, and quaternions. pub trait MetricSpace: Sized { /// The metric to be returned by the `distance` function. - type Metric: BaseFloat; + type Metric; /// Returns the squared distance. /// @@ -205,7 +205,10 @@ pub trait MetricSpace: Sized { fn distance2(self, other: Self) -> Self::Metric; /// The distance between two values. - fn distance(self, other: Self) -> Self::Metric { + fn distance(self, other: Self) -> Self::Metric + where + Self::Metric: Float, + { Float::sqrt(Self::distance2(self, other)) } } @@ -220,18 +223,17 @@ pub trait MetricSpace: Sized { pub trait InnerSpace: VectorSpace where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - ::Scalar: BaseFloat, Self: MetricSpace::Scalar>, - // Self: approx::AbsDiffEq::Scalar>, - // Self: approx::RelativeEq::Scalar>, - Self: approx::UlpsEq::Scalar>, { /// Vector dot (or inner) product. fn dot(self, other: Self) -> Self::Scalar; /// Returns `true` if the vector is perpendicular (at right angles) to the /// other vector. - fn is_perpendicular(self, other: Self) -> bool { + fn is_perpendicular(self, other: Self) -> bool + where + Self::Scalar: approx::UlpsEq, + { ulps_eq!(Self::dot(self, other), &Self::Scalar::zero()) } @@ -245,29 +247,14 @@ where Self::dot(self, self) } - /// The distance from the tail to the tip of the vector. - #[inline] - fn magnitude(self) -> Self::Scalar { - Float::sqrt(self.magnitude2()) - } - /// Returns the angle between two vectors in radians. - fn angle(self, other: Self) -> Rad { + fn angle(self, other: Self) -> Rad + where + Self::Scalar: BaseFloat, + { Rad::acos(Self::dot(self, other) / (self.magnitude() * other.magnitude())) } - /// Returns a vector with the same direction, but with a magnitude of `1`. - #[inline] - fn normalize(self) -> Self { - self.normalize_to(Self::Scalar::one()) - } - - /// Returns a vector with the same direction and a given magnitude. - #[inline] - fn normalize_to(self, magnitude: Self::Scalar) -> Self { - self * (magnitude / self.magnitude()) - } - /// Returns the /// [vector projection](https://en.wikipedia.org/wiki/Vector_projection) /// of the current inner space projected onto the supplied argument. @@ -275,6 +262,33 @@ where fn project_on(self, other: Self) -> Self { other * (self.dot(other) / other.magnitude2()) } + + /// The distance from the tail to the tip of the vector. + #[inline] + fn magnitude(self) -> Self::Scalar + where + Self::Scalar: Float, + { + Float::sqrt(self.magnitude2()) + } + + /// Returns a vector with the same direction, but with a magnitude of `1`. + #[inline] + fn normalize(self) -> Self + where + Self::Scalar: Float, + { + self.normalize_to(Self::Scalar::one()) + } + + /// Returns a vector with the same direction and a given magnitude. + #[inline] + fn normalize_to(self, magnitude: Self::Scalar) -> Self + where + Self::Scalar: Float, + { + self * (magnitude / self.magnitude()) + } } /// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space) @@ -427,14 +441,11 @@ where /// see `SquareMatrix`. pub trait Matrix: VectorSpace where - Self::Scalar: BaseFloat, + Self::Scalar: Float, // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: Index::Column>, Self: IndexMut::Column>, - Self: approx::AbsDiffEq::Scalar>, - Self: approx::RelativeEq::Scalar>, - Self: approx::UlpsEq::Scalar>, { /// The row vector of the matrix. type Row: VectorSpace + Array; @@ -482,7 +493,7 @@ where /// A column-major major matrix where the rows and column vectors are of the same dimensions. pub trait SquareMatrix where - Self::Scalar: BaseFloat, + Self::Scalar: Float, Self: One, Self: iter::Product, @@ -543,14 +554,20 @@ where /// Test if this matrix is invertible. #[inline] - fn is_invertible(&self) -> bool { + fn is_invertible(&self) -> bool + where + Self::Scalar: approx::UlpsEq, + { ulps_ne!(self.determinant(), &Self::Scalar::zero()) } /// Test if this matrix is the identity matrix. That is, it is diagonal /// and every element in the diagonal is one. #[inline] - fn is_identity(&self) -> bool { + fn is_identity(&self) -> bool + where + Self: approx::UlpsEq, + { ulps_eq!(self, &Self::identity()) } @@ -607,7 +624,11 @@ where #[inline] fn normalize_signed(self) -> Self { let rem = self.normalize(); - if Self::turn_div_2() < rem { rem - Self::full_turn() } else { rem } + if Self::turn_div_2() < rem { + rem - Self::full_turn() + } else { + rem + } } /// Return the angle rotated by half a turn. diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/transform.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/transform.rs new file mode 100644 index 0000000..151bf3d --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/transform.rs @@ -0,0 +1,432 @@ +// Copyright 2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use structure::*; + +use approx; +use matrix::{Matrix2, Matrix3, Matrix4}; +use num::{BaseFloat, BaseNum}; +use point::{Point2, Point3}; +use rotation::*; +use vector::{Vector2, Vector3}; + +use std::ops::Mul; + +/// A trait representing an [affine +/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that +/// can be applied to points or vectors. An affine transformation is one which +pub trait Transform: Sized + One { + /// Create a transformation that rotates a vector to look at `center` from + /// `eye`, using `up` for orientation. + #[deprecated = "Use look_at_rh or look_at_lh"] + fn look_at(eye: P, center: P, up: P::Diff) -> Self; + + /// Create a transformation that rotates a vector to look at `center` from + /// `eye`, using `up` for orientation. + fn look_at_rh(eye: P, center: P, up: P::Diff) -> Self; + + /// Create a transformation that rotates a vector to look at `center` from + /// `eye`, using `up` for orientation. + fn look_at_lh(eye: P, center: P, up: P::Diff) -> Self; + + /// Transform a vector using this transform. + fn transform_vector(&self, vec: P::Diff) -> P::Diff; + + /// Inverse transform a vector using this transform + fn inverse_transform_vector(&self, vec: P::Diff) -> Option { + self.inverse_transform() + .and_then(|inverse| Some(inverse.transform_vector(vec))) + } + + /// Transform a point using this transform. + fn transform_point(&self, point: P) -> P; + + /// Combine this transform with another, yielding a new transformation + /// which has the effects of both. + fn concat(&self, other: &Self) -> Self; + + /// Create a transform that "un-does" this one. + fn inverse_transform(&self) -> Option; + + /// Combine this transform with another, in-place. + #[inline] + fn concat_self(&mut self, other: &Self) { + *self = Self::concat(self, other); + } +} + +/// A generic transformation consisting of a rotation, +/// displacement vector and scale amount. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Decomposed { + pub scale: V::Scalar, + pub rot: R, + pub disp: V, +} + +impl> One for Decomposed +where + P::Scalar: BaseFloat, +{ + fn one() -> Self { + Decomposed { + scale: P::Scalar::one(), + rot: R::one(), + disp: P::Diff::zero(), + } + } +} + +impl> Mul for Decomposed +where + P::Scalar: BaseFloat, + P::Diff: VectorSpace, +{ + type Output = Self; + + /// Multiplies the two transforms together. + /// The result should be as if the two transforms were converted + /// to matrices, then multiplied, then converted back with + /// a (currently nonexistent) function that tries to convert + /// a matrix into a `Decomposed`. + fn mul(self, rhs: Decomposed) -> Self::Output { + self.concat(&rhs) + } +} + +impl> Transform

for Decomposed +where + P::Scalar: BaseFloat, + P::Diff: VectorSpace, +{ + #[inline] + fn look_at(eye: P, center: P, up: P::Diff) -> Decomposed { + let rot = R::look_at(center - eye, up); + let disp = rot.rotate_vector(P::origin() - eye); + Decomposed { + scale: P::Scalar::one(), + rot: rot, + disp: disp, + } + } + + #[inline] + fn look_at_lh(eye: P, center: P, up: P::Diff) -> Decomposed { + let rot = R::look_at(center - eye, up); + let disp = rot.rotate_vector(P::origin() - eye); + Decomposed { + scale: P::Scalar::one(), + rot: rot, + disp: disp, + } + } + + #[inline] + fn look_at_rh(eye: P, center: P, up: P::Diff) -> Decomposed { + let rot = R::look_at(eye - center, up); + let disp = rot.rotate_vector(P::origin() - eye); + Decomposed { + scale: P::Scalar::one(), + rot: rot, + disp: disp, + } + } + + #[inline] + fn transform_vector(&self, vec: P::Diff) -> P::Diff { + self.rot.rotate_vector(vec * self.scale) + } + + #[inline] + fn inverse_transform_vector(&self, vec: P::Diff) -> Option { + if ulps_eq!(self.scale, &P::Scalar::zero()) { + None + } else { + Some(self.rot.invert().rotate_vector(vec / self.scale)) + } + } + + #[inline] + fn transform_point(&self, point: P) -> P { + self.rot.rotate_point(point * self.scale) + self.disp + } + + fn concat(&self, other: &Decomposed) -> Decomposed { + Decomposed { + scale: self.scale * other.scale, + rot: self.rot * other.rot, + disp: self.rot.rotate_vector(other.disp * self.scale) + self.disp, + } + } + + fn inverse_transform(&self) -> Option> { + if ulps_eq!(self.scale, &P::Scalar::zero()) { + None + } else { + let s = P::Scalar::one() / self.scale; + let r = self.rot.invert(); + let d = r.rotate_vector(self.disp.clone()) * -s; + Some(Decomposed { + scale: s, + rot: r, + disp: d, + }) + } + } +} + +pub trait Transform2: + Transform::Scalar>> + Into::Scalar>> +{ + type Scalar: BaseNum; +} +pub trait Transform3: + Transform::Scalar>> + Into::Scalar>> +{ + type Scalar: BaseNum; +} + +impl> From, R>> for Matrix3 { + fn from(dec: Decomposed, R>) -> Matrix3 { + let m: Matrix2<_> = dec.rot.into(); + let mut m: Matrix3<_> = (&m * dec.scale).into(); + m.z = dec.disp.extend(S::one()); + m + } +} + +impl> From, R>> for Matrix4 { + fn from(dec: Decomposed, R>) -> Matrix4 { + let m: Matrix3<_> = dec.rot.into(); + let mut m: Matrix4<_> = (&m * dec.scale).into(); + m.w = dec.disp.extend(S::one()); + m + } +} + +impl> Transform2 for Decomposed, R> { + type Scalar = S; +} + +impl> Transform3 for Decomposed, R> { + type Scalar = S; +} + +impl approx::AbsDiffEq for Decomposed +where + S: approx::AbsDiffEq, + S::Scalar: approx::AbsDiffEq, + R: approx::AbsDiffEq, +{ + type Epsilon = E; + + #[inline] + fn default_epsilon() -> E { + E::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: E) -> bool { + S::Scalar::abs_diff_eq(&self.scale, &other.scale, epsilon) + && R::abs_diff_eq(&self.rot, &other.rot, epsilon) + && S::abs_diff_eq(&self.disp, &other.disp, epsilon) + } +} + +impl approx::RelativeEq for Decomposed +where + S: approx::RelativeEq, + S::Scalar: approx::RelativeEq, + R: approx::RelativeEq, +{ + #[inline] + fn default_max_relative() -> E { + E::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: E, max_relative: E) -> bool { + S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative) + && R::relative_eq(&self.rot, &other.rot, epsilon, max_relative) + && S::relative_eq(&self.disp, &other.disp, epsilon, max_relative) + } +} + +impl approx::UlpsEq for Decomposed +where + S: approx::UlpsEq, + S::Scalar: approx::UlpsEq, + R: approx::UlpsEq, +{ + #[inline] + fn default_max_ulps() -> u32 { + E::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: E, max_ulps: u32) -> bool { + S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps) + && R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps) + && S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps) + } +} + +#[cfg(feature = "serde")] +#[doc(hidden)] +mod serde_ser { + use super::Decomposed; + use serde::ser::SerializeStruct; + use serde::{self, Serialize}; + use structure::VectorSpace; + + impl Serialize for Decomposed + where + V: Serialize + VectorSpace, + V::Scalar: Serialize, + R: Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut struc = serializer.serialize_struct("Decomposed", 3)?; + struc.serialize_field("scale", &self.scale)?; + struc.serialize_field("rot", &self.rot)?; + struc.serialize_field("disp", &self.disp)?; + struc.end() + } + } +} + +#[cfg(feature = "serde")] +#[doc(hidden)] +mod serde_de { + use super::Decomposed; + use serde::{self, Deserialize}; + use std::fmt; + use std::marker::PhantomData; + use structure::VectorSpace; + + enum DecomposedField { + Scale, + Rot, + Disp, + } + + impl<'a> Deserialize<'a> for DecomposedField { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'a>, + { + struct DecomposedFieldVisitor; + + impl<'b> serde::de::Visitor<'b> for DecomposedFieldVisitor { + type Value = DecomposedField; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`scale`, `rot` or `disp`") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + match value { + "scale" => Ok(DecomposedField::Scale), + "rot" => Ok(DecomposedField::Rot), + "disp" => Ok(DecomposedField::Disp), + _ => Err(serde::de::Error::custom("expected scale, rot or disp")), + } + } + } + + deserializer.deserialize_str(DecomposedFieldVisitor) + } + } + + impl<'a, S: VectorSpace, R> Deserialize<'a> for Decomposed + where + S: Deserialize<'a>, + S::Scalar: Deserialize<'a>, + R: Deserialize<'a>, + { + fn deserialize(deserializer: D) -> Result, D::Error> + where + D: serde::de::Deserializer<'a>, + { + const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"]; + deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData)) + } + } + + struct DecomposedVisitor(PhantomData<(S, R)>); + + impl<'a, S: VectorSpace, R> serde::de::Visitor<'a> for DecomposedVisitor + where + S: Deserialize<'a>, + S::Scalar: Deserialize<'a>, + R: Deserialize<'a>, + { + type Value = Decomposed; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`scale`, `rot` and `disp` fields") + } + + fn visit_map(self, mut visitor: V) -> Result, V::Error> + where + V: serde::de::MapAccess<'a>, + { + let mut scale = None; + let mut rot = None; + let mut disp = None; + + while let Some(key) = visitor.next_key()? { + match key { + DecomposedField::Scale => { + scale = Some(visitor.next_value()?); + } + DecomposedField::Rot => { + rot = Some(visitor.next_value()?); + } + DecomposedField::Disp => { + disp = Some(visitor.next_value()?); + } + } + } + + let scale = match scale { + Some(scale) => scale, + None => return Err(serde::de::Error::missing_field("scale")), + }; + + let rot = match rot { + Some(rot) => rot, + None => return Err(serde::de::Error::missing_field("rot")), + }; + + let disp = match disp { + Some(disp) => disp, + None => return Err(serde::de::Error::missing_field("disp")), + }; + + Ok(Decomposed { + scale: scale, + rot: rot, + disp: disp, + }) + } + } +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/vector.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/vector.rs new file mode 100644 index 0000000..adcc581 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/vector.rs @@ -0,0 +1,982 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use num_traits::{Bounded, Float, NumCast}; +#[cfg(feature = "rand")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; +use std::fmt; +use std::iter; +use std::mem; +use std::ops::*; + +use structure::*; + +use angle::Rad; +use approx; +use num::{BaseFloat, BaseNum}; + +#[cfg(feature = "mint")] +use mint; + +/// A 1-dimensional vector. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Vector1 { + /// The x component of the vector. + pub x: S, +} + +/// A 2-dimensional vector. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Vector2 { + /// The x component of the vector. + pub x: S, + /// The y component of the vector. + pub y: S, +} + +/// A 3-dimensional vector. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Vector3 { + /// The x component of the vector. + pub x: S, + /// The y component of the vector. + pub y: S, + /// The z component of the vector. + pub z: S, +} + +/// A 4-dimensional vector. +/// +/// This type is marked as `#[repr(C)]`. +#[repr(C)] +#[derive(PartialEq, Eq, Copy, Clone, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Vector4 { + /// The x component of the vector. + pub x: S, + /// The y component of the vector. + pub y: S, + /// The z component of the vector. + pub z: S, + /// The w component of the vector. + pub w: S, +} + +// Utility macro for generating associated functions for the vectors +macro_rules! impl_vector { + ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { + impl $VectorN { + /// Construct a new vector, using the provided values. + #[inline] + pub const fn new($($field: S),+) -> $VectorN { + $VectorN { $($field: $field),+ } + } + + /// Perform the given operation on each field in the vector, returning a new point + /// constructed from the operations. + #[inline] + pub fn map(self, mut f: F) -> $VectorN + where F: FnMut(S) -> U + { + $VectorN { $($field: f(self.$field)),+ } + } + + /// Construct a new vector where each component is the result of + /// applying the given operation to each pair of components of the + /// given vectors. + #[inline] + pub fn zip(self, v2: $VectorN, mut f: F) -> $VectorN + where F: FnMut(S, S2) -> S3 + { + $VectorN { $($field: f(self.$field, v2.$field)),+ } + } + } + + /// The short constructor. + #[inline] + pub const fn $constructor($($field: S),+) -> $VectorN { + $VectorN::new($($field),+) + } + + impl $VectorN { + /// Component-wise casting to another type. + #[inline] + pub fn cast(&self) -> Option<$VectorN> { + $( + let $field = match NumCast::from(self.$field) { + Some(field) => field, + None => return None + }; + )+ + Some($VectorN { $($field),+ }) + } + } + + impl MetricSpace for $VectorN { + type Metric = S; + + #[inline] + fn distance2(self, other: Self) -> S { + (other - self).magnitude2() + } + } + + impl Array for $VectorN { + type Element = S; + + #[inline] + fn len() -> usize { + $n + } + + #[inline] + fn from_value(scalar: S) -> $VectorN { + $VectorN { $($field: scalar),+ } + } + + #[inline] + fn sum(self) -> S where S: Add { + fold_array!(add, { $(self.$field),+ }) + } + + #[inline] + fn product(self) -> S where S: Mul { + fold_array!(mul, { $(self.$field),+ }) + } + + fn is_finite(&self) -> bool where S: Float { + $(self.$field.is_finite())&&+ + } + } + + impl Zero for $VectorN { + #[inline] + fn zero() -> $VectorN { + $VectorN::from_value(S::zero()) + } + + #[inline] + fn is_zero(&self) -> bool { + *self == $VectorN::zero() + } + } + + impl iter::Sum<$VectorN> for $VectorN { + #[inline] + fn sum>>(iter: I) -> $VectorN { + iter.fold($VectorN::zero(), Add::add) + } + } + + impl<'a, S: 'a + BaseNum> iter::Sum<&'a $VectorN> for $VectorN { + #[inline] + fn sum>>(iter: I) -> $VectorN { + iter.fold($VectorN::zero(), Add::add) + } + } + + impl VectorSpace for $VectorN { + type Scalar = S; + } + + impl> Neg for $VectorN { + type Output = $VectorN; + + #[inline] + default_fn!( neg(self) -> $VectorN { $VectorN::new($(-self.$field),+) } ); + } + + impl approx::AbsDiffEq for $VectorN { + type Epsilon = S::Epsilon; + + #[inline] + fn default_epsilon() -> S::Epsilon { + S::default_epsilon() + } + + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { + $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ + } + } + + impl approx::RelativeEq for $VectorN { + #[inline] + fn default_max_relative() -> S::Epsilon { + S::default_max_relative() + } + + #[inline] + fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { + $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ + } + } + + impl approx::UlpsEq for $VectorN { + #[inline] + fn default_max_ulps() -> u32 { + S::default_max_ulps() + } + + #[inline] + fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { + $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ + } + } + + #[cfg(feature = "rand")] + impl Distribution<$VectorN> for Standard + where Standard: Distribution, + S: BaseFloat { + #[inline] + fn sample(&self, rng: &mut R) -> $VectorN { + $VectorN { $($field: rng.gen()),+ } + } + } + + impl Bounded for $VectorN { + #[inline] + fn min_value() -> $VectorN { + $VectorN { $($field: S::min_value()),+ } + } + + #[inline] + fn max_value() -> $VectorN { + $VectorN { $($field: S::max_value()),+ } + } + } + + impl_operator!( Add<$VectorN > for $VectorN { + fn add(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field + rhs.$field),+) } + }); + impl_assignment_operator!( AddAssign<$VectorN > for $VectorN { + fn add_assign(&mut self, other) { $(self.$field += other.$field);+ } + }); + + impl_operator!( Sub<$VectorN > for $VectorN { + fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } + }); + impl_assignment_operator!( SubAssign<$VectorN > for $VectorN { + fn sub_assign(&mut self, other) { $(self.$field -= other.$field);+ } + }); + + impl_operator!( Mul for $VectorN { + fn mul(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field * scalar),+) } + }); + impl_assignment_operator!( MulAssign for $VectorN { + fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } + }); + + impl_operator!( Div for $VectorN { + fn div(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field / scalar),+) } + }); + impl_assignment_operator!( DivAssign for $VectorN { + fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } + }); + + impl_operator!( Rem for $VectorN { + fn rem(vector, scalar) -> $VectorN { $VectorN::new($(vector.$field % scalar),+) } + }); + impl_assignment_operator!( RemAssign for $VectorN { + fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } + }); + + impl ElementWise for $VectorN { + #[inline] default_fn!( add_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field + rhs.$field),+) } ); + #[inline] default_fn!( sub_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field - rhs.$field),+) } ); + #[inline] default_fn!( mul_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field * rhs.$field),+) } ); + #[inline] default_fn!( div_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field / rhs.$field),+) } ); + #[inline] fn rem_element_wise(self, rhs: $VectorN) -> $VectorN { $VectorN::new($(self.$field % rhs.$field),+) } + + #[inline] default_fn!( add_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field += rhs.$field);+ } ); + #[inline] default_fn!( sub_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field -= rhs.$field);+ } ); + #[inline] default_fn!( mul_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field *= rhs.$field);+ } ); + #[inline] default_fn!( div_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field /= rhs.$field);+ } ); + #[inline] fn rem_assign_element_wise(&mut self, rhs: $VectorN) { $(self.$field %= rhs.$field);+ } + } + + impl ElementWise for $VectorN { + #[inline] default_fn!( add_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field + rhs),+) } ); + #[inline] default_fn!( sub_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field - rhs),+) } ); + #[inline] default_fn!( mul_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field * rhs),+) } ); + #[inline] default_fn!( div_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field / rhs),+) } ); + #[inline] fn rem_element_wise(self, rhs: S) -> $VectorN { $VectorN::new($(self.$field % rhs),+) } + + #[inline] default_fn!( add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } ); + #[inline] default_fn!( sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } ); + #[inline] default_fn!( mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } ); + #[inline] default_fn!( div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } ); + #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } + } + + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + impl_scalar_ops!($VectorN { $($field),+ }); + + impl_index_operators!($VectorN, $n, S, usize); + impl_index_operators!($VectorN, $n, [S], Range); + impl_index_operators!($VectorN, $n, [S], RangeTo); + impl_index_operators!($VectorN, $n, [S], RangeFrom); + impl_index_operators!($VectorN, $n, [S], RangeFull); + } +} + +macro_rules! impl_scalar_ops { + ($VectorN:ident<$S:ident> { $($field:ident),+ }) => { + impl_operator!(Mul<$VectorN<$S>> for $S { + fn mul(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar * vector.$field),+) } + }); + impl_operator!(Div<$VectorN<$S>> for $S { + fn div(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar / vector.$field),+) } + }); + impl_operator!(Rem<$VectorN<$S>> for $S { + fn rem(scalar, vector) -> $VectorN<$S> { $VectorN::new($(scalar % vector.$field),+) } + }); + }; +} + +impl_vector!(Vector1 { x }, 1, vec1); +impl_vector!(Vector2 { x, y }, 2, vec2); +impl_vector!(Vector3 { x, y, z }, 3, vec3); +impl_vector!(Vector4 { x, y, z, w }, 4, vec4); + +impl_fixed_array_conversions!(Vector1 { x: 0 }, 1); +impl_fixed_array_conversions!(Vector2 { x: 0, y: 1 }, 2); +impl_fixed_array_conversions!(Vector3 { x: 0, y: 1, z: 2 }, 3); +impl_fixed_array_conversions!(Vector4 { x: 0, y: 1, z: 2, w: 3 }, 4); + +impl_tuple_conversions!(Vector1 { x }, (S,)); +impl_tuple_conversions!(Vector2 { x, y }, (S, S)); +impl_tuple_conversions!(Vector3 { x, y, z }, (S, S, S)); +impl_tuple_conversions!(Vector4 { x, y, z, w }, (S, S, S, S)); + +impl Vector1 { + /// A unit vector in the `x` direction. + #[inline] + pub fn unit_x() -> Vector1 { + Vector1::new(S::one()) + } + + impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, x); +} + +impl Vector2 { + /// A unit vector in the `x` direction. + #[inline] + pub fn unit_x() -> Vector2 { + Vector2::new(S::one(), S::zero()) + } + + /// A unit vector in the `y` direction. + #[inline] + pub fn unit_y() -> Vector2 { + Vector2::new(S::zero(), S::one()) + } + + /// The perpendicular dot product of the vector and `other`. + #[inline] + pub fn perp_dot(self, other: Vector2) -> S { + (self.x * other.y) - (self.y * other.x) + } + + /// Create a `Vector3`, using the `x` and `y` values from this vector, and the + /// provided `z`. + #[inline] + pub fn extend(self, z: S) -> Vector3 { + Vector3::new(self.x, self.y, z) + } + + impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xy); +} + +impl Vector3 { + /// A unit vector in the `x` direction. + #[inline] + pub fn unit_x() -> Vector3 { + Vector3::new(S::one(), S::zero(), S::zero()) + } + + /// A unit vector in the `y` direction. + #[inline] + pub fn unit_y() -> Vector3 { + Vector3::new(S::zero(), S::one(), S::zero()) + } + + /// A unit vector in the `z` direction. + #[inline] + pub fn unit_z() -> Vector3 { + Vector3::new(S::zero(), S::zero(), S::one()) + } + + /// Returns the cross product of the vector and `other`. + #[inline] + pub fn cross(self, other: Vector3) -> Vector3 { + Vector3::new( + (self.y * other.z) - (self.z * other.y), + (self.z * other.x) - (self.x * other.z), + (self.x * other.y) - (self.y * other.x), + ) + } + + /// Create a `Vector4`, using the `x`, `y` and `z` values from this vector, and the + /// provided `w`. + #[inline] + pub fn extend(self, w: S) -> Vector4 { + Vector4::new(self.x, self.y, self.z, w) + } + + /// Create a `Vector2`, dropping the `z` value. + #[inline] + pub fn truncate(self) -> Vector2 { + Vector2::new(self.x, self.y) + } + + impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xyz); +} + +impl Vector4 { + /// A unit vector in the `x` direction. + #[inline] + pub fn unit_x() -> Vector4 { + Vector4::new(S::one(), S::zero(), S::zero(), S::zero()) + } + + /// A unit vector in the `y` direction. + #[inline] + pub fn unit_y() -> Vector4 { + Vector4::new(S::zero(), S::one(), S::zero(), S::zero()) + } + + /// A unit vector in the `z` direction. + #[inline] + pub fn unit_z() -> Vector4 { + Vector4::new(S::zero(), S::zero(), S::one(), S::zero()) + } + + /// A unit vector in the `w` direction. + #[inline] + pub fn unit_w() -> Vector4 { + Vector4::new(S::zero(), S::zero(), S::zero(), S::one()) + } + + /// Create a `Vector3`, dropping the `w` value. + #[inline] + pub fn truncate(self) -> Vector3 { + Vector3::new(self.x, self.y, self.z) + } + + /// Create a `Vector3`, dropping the nth element. + #[inline] + pub fn truncate_n(&self, n: isize) -> Vector3 { + match n { + 0 => Vector3::new(self.y, self.z, self.w), + 1 => Vector3::new(self.x, self.z, self.w), + 2 => Vector3::new(self.x, self.y, self.w), + 3 => Vector3::new(self.x, self.y, self.z), + _ => panic!("{:?} is out of range", n), + } + } + + impl_swizzle_functions!(Vector1, Vector2, Vector3, Vector4, S, xyzw); +} + +/// Dot product of two vectors. +#[inline] +pub fn dot(a: V, b: V) -> V::Scalar +where + V::Scalar: BaseFloat, +{ + V::dot(a, b) +} + +impl InnerSpace for Vector1 { + #[inline] + fn dot(self, other: Vector1) -> S { + Vector1::mul_element_wise(self, other).sum() + } +} + +impl InnerSpace for Vector2 { + #[inline] + fn dot(self, other: Vector2) -> S { + Vector2::mul_element_wise(self, other).sum() + } + + #[inline] + fn angle(self, other: Vector2) -> Rad + where + S: BaseFloat, + { + Rad::atan2(Self::perp_dot(self, other), Self::dot(self, other)) + } +} + +impl InnerSpace for Vector3 { + #[inline] + fn dot(self, other: Vector3) -> S { + Vector3::mul_element_wise(self, other).sum() + } + + #[inline] + fn angle(self, other: Vector3) -> Rad + where + S: BaseFloat, + { + Rad::atan2(self.cross(other).magnitude(), Self::dot(self, other)) + } +} + +impl InnerSpace for Vector4 { + #[inline] + fn dot(self, other: Vector4) -> S { + Vector4::mul_element_wise(self, other).sum() + } +} + +impl fmt::Debug for Vector1 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Vector1 ")?; + <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Vector2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Vector2 ")?; + <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Vector3 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Vector3 ")?; + <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +impl fmt::Debug for Vector4 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Vector4 ")?; + <[S; 4] as fmt::Debug>::fmt(self.as_ref(), f) + } +} + +#[cfg(feature = "mint")] +impl_mint_conversions!(Vector2 { x, y }, Vector2); +#[cfg(feature = "mint")] +impl_mint_conversions!(Vector3 { x, y, z }, Vector3); +#[cfg(feature = "mint")] +impl_mint_conversions!(Vector4 { x, y, z, w }, Vector4); + +#[cfg(test)] +mod tests { + mod vector2 { + use vector::*; + + const VECTOR2: Vector2 = Vector2 { x: 1, y: 2 }; + + #[test] + fn test_index() { + assert_eq!(VECTOR2[0], VECTOR2.x); + assert_eq!(VECTOR2[1], VECTOR2.y); + } + + #[test] + fn test_index_mut() { + let mut v = VECTOR2; + *&mut v[0] = 0; + assert_eq!(v, [0, 2].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + VECTOR2[2]; + } + + #[test] + fn test_index_range() { + assert_eq!(&VECTOR2[..0], &[]); + assert_eq!(&VECTOR2[..1], &[1]); + assert_eq!(VECTOR2[..0].len(), 0); + assert_eq!(VECTOR2[..1].len(), 1); + assert_eq!(&VECTOR2[2..], &[]); + assert_eq!(&VECTOR2[1..], &[2]); + assert_eq!(VECTOR2[2..].len(), 0); + assert_eq!(VECTOR2[1..].len(), 1); + assert_eq!(&VECTOR2[..], &[1, 2]); + assert_eq!(VECTOR2[..].len(), 2); + } + + #[test] + fn test_into() { + let v = VECTOR2; + { + let v: [i32; 2] = v.into(); + assert_eq!(v, [1, 2]); + } + { + let v: (i32, i32) = v.into(); + assert_eq!(v, (1, 2)); + } + } + + #[test] + fn test_as_ref() { + let v = VECTOR2; + { + let v: &[i32; 2] = v.as_ref(); + assert_eq!(v, &[1, 2]); + } + { + let v: &(i32, i32) = v.as_ref(); + assert_eq!(v, &(1, 2)); + } + } + + #[test] + fn test_as_mut() { + let mut v = VECTOR2; + { + let v: &mut [i32; 2] = v.as_mut(); + assert_eq!(v, &mut [1, 2]); + } + { + let v: &mut (i32, i32) = v.as_mut(); + assert_eq!(v, &mut (1, 2)); + } + } + + #[test] + fn test_from() { + assert_eq!(Vector2::from([1, 2]), VECTOR2); + { + let v = &[1, 2]; + let v: &Vector2<_> = From::from(v); + assert_eq!(v, &VECTOR2); + } + { + let v = &mut [1, 2]; + let v: &mut Vector2<_> = From::from(v); + assert_eq!(v, &VECTOR2); + } + assert_eq!(Vector2::from((1, 2)), VECTOR2); + { + let v = &(1, 2); + let v: &Vector2<_> = From::from(v); + assert_eq!(v, &VECTOR2); + } + { + let v = &mut (1, 2); + let v: &mut Vector2<_> = From::from(v); + assert_eq!(v, &VECTOR2); + } + } + + #[test] + fn test_is_finite() { + use num_traits::Float; + assert!(!Vector2::from([Float::nan(), 1.0]).is_finite()); + assert!(!Vector2::from([1.0, Float::infinity()]).is_finite()); + assert!(Vector2::from([-1.0, 1.0]).is_finite()); + } + + #[test] + fn test_zip() { + assert_eq!( + Vector2::new(true, false), + Vector2::new(-2, 1).zip(Vector2::new(-1, -1), |a, b| a < b) + ); + } + } + + mod vector3 { + use vector::*; + + const VECTOR3: Vector3 = Vector3 { x: 1, y: 2, z: 3 }; + + #[test] + fn test_index() { + assert_eq!(VECTOR3[0], VECTOR3.x); + assert_eq!(VECTOR3[1], VECTOR3.y); + assert_eq!(VECTOR3[2], VECTOR3.z); + } + + #[test] + fn test_index_mut() { + let mut v = VECTOR3; + *&mut v[1] = 0; + assert_eq!(v, [1, 0, 3].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + VECTOR3[3]; + } + + #[test] + fn test_index_range() { + assert_eq!(&VECTOR3[..1], &[1]); + assert_eq!(&VECTOR3[..2], &[1, 2]); + assert_eq!(VECTOR3[..1].len(), 1); + assert_eq!(VECTOR3[..2].len(), 2); + assert_eq!(&VECTOR3[2..], &[3]); + assert_eq!(&VECTOR3[1..], &[2, 3]); + assert_eq!(VECTOR3[2..].len(), 1); + assert_eq!(VECTOR3[1..].len(), 2); + assert_eq!(&VECTOR3[..], &[1, 2, 3]); + assert_eq!(VECTOR3[..].len(), 3); + } + + #[test] + fn test_into() { + let v = VECTOR3; + { + let v: [i32; 3] = v.into(); + assert_eq!(v, [1, 2, 3]); + } + { + let v: (i32, i32, i32) = v.into(); + assert_eq!(v, (1, 2, 3)); + } + } + + #[test] + fn test_as_ref() { + let v = VECTOR3; + { + let v: &[i32; 3] = v.as_ref(); + assert_eq!(v, &[1, 2, 3]); + } + { + let v: &(i32, i32, i32) = v.as_ref(); + assert_eq!(v, &(1, 2, 3)); + } + } + + #[test] + fn test_as_mut() { + let mut v = VECTOR3; + { + let v: &mut [i32; 3] = v.as_mut(); + assert_eq!(v, &mut [1, 2, 3]); + } + { + let v: &mut (i32, i32, i32) = v.as_mut(); + assert_eq!(v, &mut (1, 2, 3)); + } + } + + #[test] + fn test_from() { + assert_eq!(Vector3::from([1, 2, 3]), VECTOR3); + { + let v = &[1, 2, 3]; + let v: &Vector3<_> = From::from(v); + assert_eq!(v, &VECTOR3); + } + { + let v = &mut [1, 2, 3]; + let v: &mut Vector3<_> = From::from(v); + assert_eq!(v, &VECTOR3); + } + assert_eq!(Vector3::from((1, 2, 3)), VECTOR3); + { + let v = &(1, 2, 3); + let v: &Vector3<_> = From::from(v); + assert_eq!(v, &VECTOR3); + } + { + let v = &mut (1, 2, 3); + let v: &mut Vector3<_> = From::from(v); + assert_eq!(v, &VECTOR3); + } + } + + #[test] + fn test_is_finite() { + use num_traits::Float; + assert!(!Vector3::from([Float::nan(), 1.0, 1.0]).is_finite()); + assert!(!Vector3::from([1.0, 1.0, Float::infinity()]).is_finite()); + assert!(Vector3::from([-1.0, 1.0, 1.0]).is_finite()); + } + + #[test] + fn test_zip() { + assert_eq!( + Vector3::new(true, false, false), + Vector3::new(-2, 1, 0).zip(Vector3::new(-1, -1, -1), |a, b| a < b) + ); + } + } + + mod vector4 { + use vector::*; + + const VECTOR4: Vector4 = Vector4 { + x: 1, + y: 2, + z: 3, + w: 4, + }; + + #[test] + fn test_index() { + assert_eq!(VECTOR4[0], VECTOR4.x); + assert_eq!(VECTOR4[1], VECTOR4.y); + assert_eq!(VECTOR4[2], VECTOR4.z); + assert_eq!(VECTOR4[3], VECTOR4.w); + } + + #[test] + fn test_index_mut() { + let mut v = VECTOR4; + *&mut v[2] = 0; + assert_eq!(v, [1, 2, 0, 4].into()); + } + + #[test] + #[should_panic] + fn test_index_out_of_bounds() { + VECTOR4[4]; + } + + #[test] + fn test_index_range() { + assert_eq!(&VECTOR4[..2], &[1, 2]); + assert_eq!(&VECTOR4[..3], &[1, 2, 3]); + assert_eq!(VECTOR4[..2].len(), 2); + assert_eq!(VECTOR4[..3].len(), 3); + assert_eq!(&VECTOR4[2..], &[3, 4]); + assert_eq!(&VECTOR4[1..], &[2, 3, 4]); + assert_eq!(VECTOR4[2..].len(), 2); + assert_eq!(VECTOR4[1..].len(), 3); + assert_eq!(&VECTOR4[..], &[1, 2, 3, 4]); + assert_eq!(VECTOR4[..].len(), 4); + } + + #[test] + fn test_into() { + let v = VECTOR4; + { + let v: [i32; 4] = v.into(); + assert_eq!(v, [1, 2, 3, 4]); + } + { + let v: (i32, i32, i32, i32) = v.into(); + assert_eq!(v, (1, 2, 3, 4)); + } + } + + #[test] + fn test_as_ref() { + let v = VECTOR4; + { + let v: &[i32; 4] = v.as_ref(); + assert_eq!(v, &[1, 2, 3, 4]); + } + { + let v: &(i32, i32, i32, i32) = v.as_ref(); + assert_eq!(v, &(1, 2, 3, 4)); + } + } + + #[test] + fn test_as_mut() { + let mut v = VECTOR4; + { + let v: &mut [i32; 4] = v.as_mut(); + assert_eq!(v, &mut [1, 2, 3, 4]); + } + { + let v: &mut (i32, i32, i32, i32) = v.as_mut(); + assert_eq!(v, &mut (1, 2, 3, 4)); + } + } + + #[test] + fn test_from() { + assert_eq!(Vector4::from([1, 2, 3, 4]), VECTOR4); + { + let v = &[1, 2, 3, 4]; + let v: &Vector4<_> = From::from(v); + assert_eq!(v, &VECTOR4); + } + { + let v = &mut [1, 2, 3, 4]; + let v: &mut Vector4<_> = From::from(v); + assert_eq!(v, &VECTOR4); + } + assert_eq!(Vector4::from((1, 2, 3, 4)), VECTOR4); + { + let v = &(1, 2, 3, 4); + let v: &Vector4<_> = From::from(v); + assert_eq!(v, &VECTOR4); + } + { + let v = &mut (1, 2, 3, 4); + let v: &mut Vector4<_> = From::from(v); + assert_eq!(v, &VECTOR4); + } + } + + #[test] + fn test_is_finite() { + use num_traits::Float; + assert!(!Vector4::from([0.0, Float::nan(), 1.0, 1.0]).is_finite()); + assert!(!Vector4::from([1.0, 1.0, Float::neg_infinity(), 0.0]).is_finite()); + assert!(Vector4::from([-1.0, 0.0, 1.0, 1.0]).is_finite()); + } + + #[test] + fn test_zip() { + assert_eq!( + Vector4::new(true, false, false, false), + Vector4::new(-2, 1, 0, 1).zip(Vector4::new(-1, -1, -1, -1), |a, b| a < b) + ); + } + + #[test] + fn test_dot() { + assert_eq!(vec3(1.0, 2.0, 3.0).dot(vec3(4.0, 5.0, 6.0)), 32.0); + assert_eq!(vec3(1, 2, 3).dot(vec3(4, 5, 6)), 32); + } + } +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/src/vector_simd.rs b/third_party/cargo/vendor/cgmath-0.18.0/src/vector_simd.rs new file mode 100644 index 0000000..70592ee --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/src/vector_simd.rs @@ -0,0 +1,393 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use vector::*; + +use structure::*; + +use std::mem; +use std::ops::*; + +use simd::f32x4 as Simdf32x4; +use simd::i32x4 as Simdi32x4; +use simd::u32x4 as Simdu32x4; + +impl From for Vector4 { + #[inline] + fn from(f: Simdf32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [f32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Vector4 { + /// Compute and return the square root of each element. + #[inline] + pub fn sqrt_element_wide(self) -> Self { + let s: Simdf32x4 = self.into(); + s.sqrt().into() + } + + /// Compute and return the reciprocal of the square root of each element. + #[inline] + pub fn rsqrt_element_wide(self) -> Self { + let s: Simdf32x4 = self.into(); + s.approx_rsqrt().into() + } + + /// Compute and return the reciprocal of each element. + #[inline] + pub fn recip_element_wide(self) -> Self { + let s: Simdf32x4 = self.into(); + s.approx_reciprocal().into() + } +} + +impl Into for Vector4 { + #[inline] + fn into(self) -> Simdf32x4 { + let self_ref: &[f32; 4] = self.as_ref(); + Simdf32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl_operator_simd! { + [Simdf32x4]; Add> for Vector4 { + fn add(lhs, rhs) -> Vector4 { + (lhs + rhs).into() + } + } +} + +impl_operator_simd! { + [Simdf32x4]; Sub> for Vector4 { + fn sub(lhs, rhs) -> Vector4 { + (lhs - rhs).into() + } + } +} + +impl_operator_simd! {@rs + [Simdf32x4]; Mul for Vector4 { + fn mul(lhs, rhs) -> Vector4 { + (lhs * rhs).into() + } + } +} + +impl_operator_simd! {@rs + [Simdf32x4]; Div for Vector4 { + fn div(lhs, rhs) -> Vector4 { + (lhs / rhs).into() + } + } +} + +impl_operator_simd! { + [Simdf32x4]; Neg for Vector4 { + fn neg(lhs) -> Vector4 { + (-lhs).into() + } + } +} + +impl AddAssign for Vector4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl SubAssign for Vector4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl MulAssign for Vector4 { + fn mul_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s * other).into(); + } +} + +impl DivAssign for Vector4 { + fn div_assign(&mut self, other: f32) { + let s: Simdf32x4 = (*self).into(); + let other = Simdf32x4::splat(other); + *self = (s / other).into(); + } +} + +impl ElementWise for Vector4 { + #[inline] + fn add_element_wise(self, rhs: Vector4) -> Vector4 { + self + rhs + } + #[inline] + fn sub_element_wise(self, rhs: Vector4) -> Vector4 { + self - rhs + } + #[inline] + fn mul_element_wise(self, rhs: Vector4) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs: Simdf32x4 = rhs.into(); + (s * rhs).into() + } + #[inline] + fn div_element_wise(self, rhs: Vector4) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs: Simdf32x4 = rhs.into(); + (s / rhs).into() + } + + #[inline] + fn add_assign_element_wise(&mut self, rhs: Vector4) { + (*self) += rhs; + } + + #[inline] + fn sub_assign_element_wise(&mut self, rhs: Vector4) { + (*self) -= rhs; + } + + #[inline] + fn mul_assign_element_wise(&mut self, rhs: Vector4) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s * rhs).into(); + } + + #[inline] + fn div_assign_element_wise(&mut self, rhs: Vector4) { + let s: Simdf32x4 = (*self).into(); + let rhs: Simdf32x4 = rhs.into(); + *self = (s * rhs).into(); + } +} + +impl ElementWise for Vector4 { + #[inline] + fn add_element_wise(self, rhs: f32) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs = Simdf32x4::splat(rhs); + (s + rhs).into() + } + + #[inline] + fn sub_element_wise(self, rhs: f32) -> Vector4 { + let s: Simdf32x4 = self.into(); + let rhs = Simdf32x4::splat(rhs); + (s - rhs).into() + } + + #[inline] + fn mul_element_wise(self, rhs: f32) -> Vector4 { + self * rhs + } + + #[inline] + fn div_element_wise(self, rhs: f32) -> Vector4 { + self / rhs + } + + #[inline] + fn add_assign_element_wise(&mut self, rhs: f32) { + let s: Simdf32x4 = (*self).into(); + let rhs = Simdf32x4::splat(rhs); + *self = (s + rhs).into(); + } + + #[inline] + fn sub_assign_element_wise(&mut self, rhs: f32) { + let s: Simdf32x4 = (*self).into(); + let rhs = Simdf32x4::splat(rhs); + *self = (s - rhs).into(); + } + + #[inline] + fn mul_assign_element_wise(&mut self, rhs: f32) { + (*self) *= rhs; + } + + #[inline] + fn div_assign_element_wise(&mut self, rhs: f32) { + (*self) /= rhs; + } +} + +impl From for Vector4 { + #[inline] + fn from(f: Simdi32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [i32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Into for Vector4 { + #[inline] + fn into(self) -> Simdi32x4 { + let self_ref: &[i32; 4] = self.as_ref(); + Simdi32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl_operator_simd! { + [Simdi32x4]; Add> for Vector4 { + fn add(lhs, rhs) -> Vector4 { + (lhs + rhs).into() + } + } +} + +impl_operator_simd! { + [Simdi32x4]; Sub> for Vector4 { + fn sub(lhs, rhs) -> Vector4 { + (lhs - rhs).into() + } + } +} + +impl_operator_simd! {@rs + [Simdi32x4]; Mul for Vector4 { + fn mul(lhs, rhs) -> Vector4 { + (lhs * rhs).into() + } + } +} + +impl_operator_simd! { + [Simdi32x4]; Neg for Vector4 { + fn neg(lhs) -> Vector4 { + (-lhs).into() + } + } +} + +impl AddAssign for Vector4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdi32x4 = (*self).into(); + let rhs: Simdi32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl SubAssign for Vector4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdi32x4 = (*self).into(); + let rhs: Simdi32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl MulAssign for Vector4 { + fn mul_assign(&mut self, other: i32) { + let s: Simdi32x4 = (*self).into(); + let other = Simdi32x4::splat(other); + *self = (s * other).into(); + } +} + +impl From for Vector4 { + #[inline] + fn from(f: Simdu32x4) -> Self { + unsafe { + let mut ret: Self = mem::uninitialized(); + { + let ret_mut: &mut [u32; 4] = ret.as_mut(); + f.store(ret_mut.as_mut(), 0 as usize); + } + ret + } + } +} + +impl Into for Vector4 { + #[inline] + fn into(self) -> Simdu32x4 { + let self_ref: &[u32; 4] = self.as_ref(); + Simdu32x4::load(self_ref.as_ref(), 0 as usize) + } +} + +impl_operator_simd! { + [Simdu32x4]; Add> for Vector4 { + fn add(lhs, rhs) -> Vector4 { + (lhs + rhs).into() + } + } +} + +impl_operator_simd! { + [Simdu32x4]; Sub> for Vector4 { + fn sub(lhs, rhs) -> Vector4 { + (lhs - rhs).into() + } + } +} + +impl_operator_simd! {@rs + [Simdu32x4]; Mul for Vector4 { + fn mul(lhs, rhs) -> Vector4 { + (lhs * rhs).into() + } + } +} + +impl AddAssign for Vector4 { + #[inline] + fn add_assign(&mut self, rhs: Self) { + let s: Simdu32x4 = (*self).into(); + let rhs: Simdu32x4 = rhs.into(); + *self = (s + rhs).into(); + } +} + +impl SubAssign for Vector4 { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + let s: Simdu32x4 = (*self).into(); + let rhs: Simdu32x4 = rhs.into(); + *self = (s - rhs).into(); + } +} + +impl MulAssign for Vector4 { + fn mul_assign(&mut self, other: u32) { + let s: Simdu32x4 = (*self).into(); + let other = Simdu32x4::splat(other); + *self = (s * other).into(); + } +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/angle.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/angle.rs old mode 100755 new mode 100644 similarity index 100% rename from third_party/cargo/vendor/cgmath-0.17.0/tests/angle.rs rename to third_party/cargo/vendor/cgmath-0.18.0/tests/angle.rs diff --git a/third_party/cargo/vendor/cgmath-0.18.0/tests/matrix.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/matrix.rs new file mode 100644 index 0000000..adcbc6a --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/matrix.rs @@ -0,0 +1,1220 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate approx; +extern crate cgmath; + +pub mod matrix2 { + use std::f64; + + use cgmath::*; + + const A: Matrix2 = Matrix2 { + x: Vector2 { + x: 1.0f64, + y: 3.0f64, + }, + y: Vector2 { + x: 2.0f64, + y: 4.0f64, + }, + }; + const B: Matrix2 = Matrix2 { + x: Vector2 { + x: 2.0f64, + y: 4.0f64, + }, + y: Vector2 { + x: 3.0f64, + y: 5.0f64, + }, + }; + const C: Matrix2 = Matrix2 { + x: Vector2 { + x: 2.0f64, + y: 1.0f64, + }, + y: Vector2 { + x: 1.0f64, + y: 2.0f64, + }, + }; + + const V: Vector2 = Vector2 { + x: 1.0f64, + y: 2.0f64, + }; + const F: f64 = 0.5; + + #[test] + fn test_neg() { + assert_eq!(-A, Matrix2::new(-1.0f64, -3.0f64, -2.0f64, -4.0f64)); + } + + #[test] + fn test_mul_scalar() { + let result = Matrix2::new(0.5f64, 1.5f64, 1.0f64, 2.0f64); + assert_eq!(A * F, result); + assert_eq!(F * A, result); + } + + #[test] + fn test_div_scalar() { + assert_eq!(A / F, Matrix2::new(2.0f64, 6.0f64, 4.0f64, 8.0f64)); + assert_eq!(4.0f64 / C, Matrix2::new(2.0f64, 4.0f64, 4.0f64, 2.0f64)); + } + + #[test] + fn test_rem_scalar() { + assert_eq!(A % 3.0f64, Matrix2::new(1.0f64, 0.0f64, 2.0f64, 1.0f64)); + assert_eq!(3.0f64 % A, Matrix2::new(0.0f64, 0.0f64, 1.0f64, 3.0f64)); + } + + #[test] + fn test_add_matrix() { + assert_eq!(A + B, Matrix2::new(3.0f64, 7.0f64, 5.0f64, 9.0f64)); + } + + #[test] + fn test_sub_matrix() { + assert_eq!(A - B, Matrix2::new(-1.0f64, -1.0f64, -1.0f64, -1.0f64)); + } + + #[test] + fn test_mul_vector() { + assert_eq!(A * V, Vector2::new(5.0f64, 11.0f64)); + } + + #[test] + fn test_mul_matrix() { + assert_eq!(A * B, Matrix2::new(10.0f64, 22.0f64, 13.0f64, 29.0f64)); + + assert_eq!(A * B, &A * &B); + } + + #[test] + fn test_sum_matrix() { + assert_eq!(A + B + C, [A, B, C].iter().sum()); + assert_eq!(A + B + C, [A, B, C].iter().cloned().sum()); + } + + #[test] + fn test_product_matrix() { + assert_eq!(A * B * C, [A, B, C].iter().product()); + assert_eq!(A * B * C, [A, B, C].iter().cloned().product()); + } + + #[test] + fn test_determinant() { + assert_eq!(A.determinant(), -2.0f64) + } + + #[test] + fn test_trace() { + assert_eq!(A.trace(), 5.0f64); + } + + #[test] + fn test_transpose() { + assert_eq!( + A.transpose(), + Matrix2::::new(1.0f64, 2.0f64, 3.0f64, 4.0f64) + ); + } + + #[test] + fn test_transpose_self() { + let mut mut_a = A; + mut_a.transpose_self(); + assert_eq!(mut_a, A.transpose()); + } + + #[test] + fn test_invert() { + assert!(Matrix2::::identity().invert().unwrap().is_identity()); + + assert_eq!( + A.invert().unwrap(), + Matrix2::new(-2.0f64, 1.5f64, 1.0f64, -0.5f64) + ); + assert!(Matrix2::new(0.0f64, 2.0f64, 0.0f64, 5.0f64) + .invert() + .is_none()); + } + + #[test] + fn test_predicates() { + assert!(Matrix2::::identity().is_identity()); + assert!(Matrix2::::identity().is_symmetric()); + assert!(Matrix2::::identity().is_diagonal()); + assert!(Matrix2::::identity().is_invertible()); + + assert!(!A.is_identity()); + assert!(!A.is_symmetric()); + assert!(!A.is_diagonal()); + assert!(A.is_invertible()); + + assert!(!C.is_identity()); + assert!(C.is_symmetric()); + assert!(!C.is_diagonal()); + assert!(C.is_invertible()); + + assert!(Matrix2::from_value(6.0f64).is_diagonal()); + } + + #[test] + fn test_from_angle() { + // Rotate the vector (1, 0) by π/2 radians to the vector (0, 1) + let rot1 = Matrix2::from_angle(Rad(0.5f64 * f64::consts::PI)); + assert_ulps_eq!(rot1 * Vector2::unit_x(), &Vector2::unit_y()); + + // Rotate the vector (-1, 0) by -π/2 radians to the vector (0, 1) + let rot2 = -rot1; + assert_ulps_eq!(rot2 * -Vector2::unit_x(), &Vector2::unit_y()); + + // Rotate the vector (1, 1) by π radians to the vector (-1, -1) + let rot3: Matrix2 = Matrix2::from_angle(Rad(f64::consts::PI)); + assert_ulps_eq!(rot3 * Vector2::new(1.0, 1.0), &Vector2::new(-1.0, -1.0)); + } + + #[test] + fn test_look_at() { + // rot should rotate unit_x() to look at the input vector + let rot = Matrix2::look_at(V, Vector2::unit_y()); + assert_eq!(rot * Vector2::unit_x(), V.normalize()); + let new_up = Vector2::new(-V.y, V.x).normalize(); + assert_eq!(rot * Vector2::unit_y(), new_up); + + let rot_down = Matrix2::look_at(V, -1.0 * Vector2::unit_y()); + assert_eq!(rot_down * Vector2::unit_x(), V.normalize()); + assert_eq!(rot_down * Vector2::unit_y(), -1.0 * new_up); + + let rot2 = Matrix2::look_at(-V, Vector2::unit_y()); + assert_eq!(rot2 * Vector2::unit_x(), (-V).normalize()); + } +} + +pub mod matrix3 { + use cgmath::*; + + const A: Matrix3 = Matrix3 { + x: Vector3 { + x: 1.0f64, + y: 4.0f64, + z: 7.0f64, + }, + y: Vector3 { + x: 2.0f64, + y: 5.0f64, + z: 8.0f64, + }, + z: Vector3 { + x: 3.0f64, + y: 6.0f64, + z: 9.0f64, + }, + }; + const B: Matrix3 = Matrix3 { + x: Vector3 { + x: 2.0f64, + y: 5.0f64, + z: 8.0f64, + }, + y: Vector3 { + x: 3.0f64, + y: 6.0f64, + z: 9.0f64, + }, + z: Vector3 { + x: 4.0f64, + y: 7.0f64, + z: 10.0f64, + }, + }; + const C: Matrix3 = Matrix3 { + x: Vector3 { + x: 2.0f64, + y: 4.0f64, + z: 6.0f64, + }, + y: Vector3 { + x: 0.0f64, + y: 2.0f64, + z: 4.0f64, + }, + z: Vector3 { + x: 0.0f64, + y: 0.0f64, + z: 1.0f64, + }, + }; + const D: Matrix3 = Matrix3 { + x: Vector3 { + x: 3.0f64, + y: 2.0f64, + z: 1.0f64, + }, + y: Vector3 { + x: 2.0f64, + y: 3.0f64, + z: 2.0f64, + }, + z: Vector3 { + x: 1.0f64, + y: 2.0f64, + z: 3.0f64, + }, + }; + + const V: Vector3 = Vector3 { + x: 1.0f64, + y: 2.0f64, + z: 3.0f64, + }; + const F: f64 = 0.5; + + #[test] + fn test_neg() { + assert_eq!( + -A, + Matrix3::new( + -1.0f64, -4.0f64, -7.0f64, -2.0f64, -5.0f64, -8.0f64, -3.0f64, -6.0f64, -9.0f64 + ) + ); + } + + #[test] + fn test_mul_scalar() { + let result = Matrix3::new( + 0.5f64, 2.0f64, 3.5f64, 1.0f64, 2.5f64, 4.0f64, 1.5f64, 3.0f64, 4.5f64, + ); + assert_eq!(A * F, result); + assert_eq!(F * A, result); + } + + #[test] + fn test_div_scalar() { + assert_eq!( + A / F, + Matrix3::new( + 2.0f64, 8.0f64, 14.0f64, 4.0f64, 10.0f64, 16.0f64, 6.0f64, 12.0f64, 18.0f64 + ) + ); + assert_eq!( + 6.0f64 / D, + Matrix3::new(2.0f64, 3.0f64, 6.0f64, 3.0f64, 2.0f64, 3.0f64, 6.0f64, 3.0f64, 2.0f64) + ); + } + + #[test] + fn test_rem_scalar() { + assert_eq!( + A % 3.0f64, + Matrix3::new(1.0f64, 1.0f64, 1.0f64, 2.0f64, 2.0f64, 2.0f64, 0.0f64, 0.0f64, 0.0f64) + ); + assert_eq!( + 9.0f64 % A, + Matrix3::new(0.0f64, 1.0f64, 2.0f64, 1.0f64, 4.0f64, 1.0f64, 0.0f64, 3.0f64, 0.0f64) + ); + } + + #[test] + fn test_add_matrix() { + assert_eq!( + A + B, + Matrix3::new( + 3.0f64, 9.0f64, 15.0f64, 5.0f64, 11.0f64, 17.0f64, 7.0f64, 13.0f64, 19.0f64 + ) + ); + } + + #[test] + fn test_sub_matrix() { + assert_eq!( + A - B, + Matrix3::new( + -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64 + ) + ); + } + + #[test] + fn test_mul_vector() { + assert_eq!(A * V, Vector3::new(14.0f64, 32.0f64, 50.0f64)); + } + + #[test] + fn test_mul_matrix() { + assert_eq!( + A * B, + Matrix3::new( + 36.0f64, 81.0f64, 126.0f64, 42.0f64, 96.0f64, 150.0f64, 48.0f64, 111.0f64, 174.0f64 + ) + ); + + assert_eq!(A * B, &A * &B); + } + + #[test] + fn test_sum_matrix() { + assert_eq!(A + B + C + D, [A, B, C, D].iter().sum()); + assert_eq!(A + B + C + D, [A, B, C, D].iter().cloned().sum()); + } + + #[test] + fn test_product_matrix() { + assert_eq!(A * B * C * D, [A, B, C, D].iter().product()); + assert_eq!(A * B * C * D, [A, B, C, D].iter().cloned().product()); + } + + #[test] + fn test_determinant() { + assert_eq!(A.determinant(), 0.0f64); + } + + #[test] + fn test_trace() { + assert_eq!(A.trace(), 15.0f64); + } + + #[test] + fn test_transpose() { + assert_eq!( + A.transpose(), + Matrix3::::new( + 1.0f64, 2.0f64, 3.0f64, 4.0f64, 5.0f64, 6.0f64, 7.0f64, 8.0f64, 9.0f64 + ) + ); + } + + #[test] + fn test_transpose_self() { + let mut mut_a = A; + mut_a.transpose_self(); + assert_eq!(mut_a, A.transpose()); + } + + #[test] + fn test_invert() { + assert!(Matrix3::::identity().invert().unwrap().is_identity()); + + assert_eq!(A.invert(), None); + + assert_eq!( + C.invert().unwrap(), + Matrix3::new(0.5f64, -1.0f64, 1.0f64, 0.0f64, 0.5f64, -2.0f64, 0.0f64, 0.0f64, 1.0f64) + ); + } + + #[test] + fn test_predicates() { + assert!(Matrix3::::identity().is_identity()); + assert!(Matrix3::::identity().is_symmetric()); + assert!(Matrix3::::identity().is_diagonal()); + assert!(Matrix3::::identity().is_invertible()); + + assert!(!A.is_identity()); + assert!(!A.is_symmetric()); + assert!(!A.is_diagonal()); + assert!(!A.is_invertible()); + + assert!(!D.is_identity()); + assert!(D.is_symmetric()); + assert!(!D.is_diagonal()); + assert!(D.is_invertible()); + + assert!(Matrix3::from_value(6.0f64).is_diagonal()); + } + + #[test] + fn test_from_translation() { + let mat = Matrix3::from_translation(Vector2::new(1.0f64, 2.0f64)); + let vertex = Vector3::new(0.0f64, 0.0f64, 1.0f64); + let res = mat * vertex; + assert_eq!(res, Vector3::new(1., 2., 1.)); + } + + mod from_axis_x { + use cgmath::*; + + fn check_from_axis_angle_x(pitch: Rad) { + let found = Matrix3::from_angle_x(pitch); + let expected = Matrix3::from(Euler { + x: pitch, + y: Rad(0.0), + z: Rad(0.0), + }); + assert_relative_eq!(found, expected, epsilon = 0.001); + } + + #[test] + fn test_zero() { + check_from_axis_angle_x(Rad(0.0)); + } + #[test] + fn test_pos_1() { + check_from_axis_angle_x(Rad(1.0)); + } + #[test] + fn test_neg_1() { + check_from_axis_angle_x(Rad(-1.0)); + } + } + + mod from_axis_y { + use cgmath::*; + + fn check_from_axis_angle_y(yaw: Rad) { + let found = Matrix3::from_angle_y(yaw); + let expected = Matrix3::from(Euler { + x: Rad(0.0), + y: yaw, + z: Rad(0.0), + }); + assert_relative_eq!(found, expected, epsilon = 0.001); + } + + #[test] + fn test_zero() { + check_from_axis_angle_y(Rad(0.0)); + } + #[test] + fn test_pos_1() { + check_from_axis_angle_y(Rad(1.0)); + } + #[test] + fn test_neg_1() { + check_from_axis_angle_y(Rad(-1.0)); + } + } + + mod from_axis_z { + use cgmath::*; + + fn check_from_axis_angle_z(roll: Rad) { + let found = Matrix3::from_angle_z(roll); + let expected = Matrix3::from(Euler { + x: Rad(0.0), + y: Rad(0.0), + z: roll, + }); + assert_relative_eq!(found, expected, epsilon = 0.001); + } + + #[test] + fn test_zero() { + check_from_axis_angle_z(Rad(0.0)); + } + #[test] + fn test_pos_1() { + check_from_axis_angle_z(Rad(1.0)); + } + #[test] + fn test_neg_1() { + check_from_axis_angle_z(Rad(-1.0)); + } + } + + mod from_axis_angle { + mod axis_x { + use cgmath::*; + + fn check_from_axis_angle_x(pitch: Rad) { + let found = Matrix3::from_axis_angle(Vector3::unit_x(), pitch); + let expected = Matrix3::from(Euler { + x: pitch, + y: Rad(0.0), + z: Rad(0.0), + }); + assert_relative_eq!(found, expected, epsilon = 0.001); + } + + #[test] + fn test_zero() { + check_from_axis_angle_x(Rad(0.0)); + } + #[test] + fn test_pos_1() { + check_from_axis_angle_x(Rad(1.0)); + } + #[test] + fn test_neg_1() { + check_from_axis_angle_x(Rad(-1.0)); + } + } + + mod axis_y { + use cgmath::*; + + fn check_from_axis_angle_y(yaw: Rad) { + let found = Matrix3::from_axis_angle(Vector3::unit_y(), yaw); + let expected = Matrix3::from(Euler { + x: Rad(0.0), + y: yaw, + z: Rad(0.0), + }); + assert_relative_eq!(found, expected, epsilon = 0.001); + } + + #[test] + fn test_zero() { + check_from_axis_angle_y(Rad(0.0)); + } + #[test] + fn test_pos_1() { + check_from_axis_angle_y(Rad(1.0)); + } + #[test] + fn test_neg_1() { + check_from_axis_angle_y(Rad(-1.0)); + } + } + + mod axis_z { + use cgmath::*; + + fn check_from_axis_angle_z(roll: Rad) { + let found = Matrix3::from_axis_angle(Vector3::unit_z(), roll); + let expected = Matrix3::from(Euler { + x: Rad(0.0), + y: Rad(0.0), + z: roll, + }); + assert_relative_eq!(found, expected, epsilon = 0.001); + } + + #[test] + fn test_zero() { + check_from_axis_angle_z(Rad(0.0)); + } + #[test] + fn test_pos_1() { + check_from_axis_angle_z(Rad(1.0)); + } + #[test] + fn test_neg_1() { + check_from_axis_angle_z(Rad(-1.0)); + } + } + } + + mod rotate_from_euler { + use cgmath::*; + + #[test] + fn test_x() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Matrix3::from(Euler::new(Deg(90.0), Deg(0.0), Deg(0.0))); + assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); + + let rot = Matrix3::from(Euler::new(Deg(-90.0), Deg(0.0), Deg(0.0))); + assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); + } + + #[test] + fn test_y() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(90.0), Deg(0.0))); + assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); + + let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(-90.0), Deg(0.0))); + assert_ulps_eq!(vec3(-1.0, 0.0, 0.0), rot * vec); + } + + #[test] + fn test_z() { + let vec = vec3(1.0, 0.0, 0.0); + + let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(0.0), Deg(90.0))); + assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); + + let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(0.0), Deg(-90.0))); + assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); + } + + // tests that the Y rotation is done after the X + #[test] + fn test_x_then_y() { + let vec = vec3(0.0, 1.0, 0.0); + + let rot = Matrix3::from(Euler::new(Deg(90.0), Deg(90.0), Deg(0.0))); + assert_ulps_eq!(vec3(0.0, 0.0, 1.0), rot * vec); + } + + // tests that the Z rotation is done after the Y + #[test] + fn test_y_then_z() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Matrix3::from(Euler::new(Deg(0.0), Deg(90.0), Deg(90.0))); + assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); + } + } + + mod rotate_from_axis_angle { + use cgmath::*; + + #[test] + fn test_x() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Matrix3::from_angle_x(Deg(90.0)); + println!("x mat: {:?}", rot); + assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); + } + + #[test] + fn test_y() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Matrix3::from_angle_y(Deg(90.0)); + assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); + } + + #[test] + fn test_z() { + let vec = vec3(1.0, 0.0, 0.0); + + let rot = Matrix3::from_angle_z(Deg(90.0)); + assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); + } + + #[test] + fn test_xy() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Matrix3::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), Deg(90.0)); + assert_ulps_eq!( + vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0), + rot * vec + ); + } + + #[test] + fn test_yz() { + let vec = vec3(1.0, 0.0, 0.0); + + let rot = Matrix3::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), Deg(-90.0)); + assert_ulps_eq!( + vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0), + rot * vec + ); + } + + #[test] + fn test_xz() { + let vec = vec3(0.0, 1.0, 0.0); + + let rot = Matrix3::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), Deg(90.0)); + assert_ulps_eq!( + vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), + rot * vec + ); + } + } + + #[test] + fn test_look_to_lh() { + let dir = Vector3::new(1.0, 2.0, 3.0).normalize(); + let up = Vector3::unit_y(); + let m = Matrix3::look_to_lh(dir, up); + + assert_ulps_eq!(m, Matrix3::from([ + [0.9486833, -0.16903085, 0.26726127], + [0.0, 0.8451542, 0.53452253], + [-0.31622776, -0.50709254, 0.8017838_f32] + ])); + + #[allow(deprecated)] + { + assert_ulps_eq!(m, Matrix3::look_at(dir, up)); + } + } + + #[test] + fn test_look_to_rh() { + let dir = Vector3::new(1.0, 2.0, 3.0).normalize(); + let up = Vector3::unit_y(); + let m = Matrix3::look_to_rh(dir, up); + + assert_ulps_eq!(m, Matrix3::from([ + [-0.9486833, -0.16903085, -0.26726127], + [0.0, 0.8451542, -0.53452253], + [0.31622776, -0.50709254, -0.8017838_f32] + ])); + } +} + +pub mod matrix4 { + use cgmath::*; + + const A: Matrix4 = Matrix4 { + x: Vector4 { + x: 1.0f64, + y: 5.0f64, + z: 9.0f64, + w: 13.0f64, + }, + y: Vector4 { + x: 2.0f64, + y: 6.0f64, + z: 10.0f64, + w: 14.0f64, + }, + z: Vector4 { + x: 3.0f64, + y: 7.0f64, + z: 11.0f64, + w: 15.0f64, + }, + w: Vector4 { + x: 4.0f64, + y: 8.0f64, + z: 12.0f64, + w: 16.0f64, + }, + }; + const B: Matrix4 = Matrix4 { + x: Vector4 { + x: 2.0f64, + y: 6.0f64, + z: 10.0f64, + w: 14.0f64, + }, + y: Vector4 { + x: 3.0f64, + y: 7.0f64, + z: 11.0f64, + w: 15.0f64, + }, + z: Vector4 { + x: 4.0f64, + y: 8.0f64, + z: 12.0f64, + w: 16.0f64, + }, + w: Vector4 { + x: 5.0f64, + y: 9.0f64, + z: 13.0f64, + w: 17.0f64, + }, + }; + const C: Matrix4 = Matrix4 { + x: Vector4 { + x: 3.0f64, + y: 2.0f64, + z: 1.0f64, + w: 1.0f64, + }, + y: Vector4 { + x: 2.0f64, + y: 3.0f64, + z: 2.0f64, + w: 2.0f64, + }, + z: Vector4 { + x: 1.0f64, + y: 2.0f64, + z: 3.0f64, + w: 3.0f64, + }, + w: Vector4 { + x: 0.0f64, + y: 1.0f64, + z: 1.0f64, + w: 0.0f64, + }, + }; + const D: Matrix4 = Matrix4 { + x: Vector4 { + x: 4.0f64, + y: 3.0f64, + z: 2.0f64, + w: 1.0f64, + }, + y: Vector4 { + x: 3.0f64, + y: 4.0f64, + z: 3.0f64, + w: 2.0f64, + }, + z: Vector4 { + x: 2.0f64, + y: 3.0f64, + z: 4.0f64, + w: 3.0f64, + }, + w: Vector4 { + x: 1.0f64, + y: 2.0f64, + z: 3.0f64, + w: 4.0f64, + }, + }; + + const V: Vector4 = Vector4 { + x: 1.0f64, + y: 2.0f64, + z: 3.0f64, + w: 4.0f64, + }; + const F: f64 = 0.5; + + #[test] + fn test_neg() { + assert_eq!( + -A, + Matrix4::new( + -1.0f64, -5.0f64, -9.0f64, -13.0f64, -2.0f64, -6.0f64, -10.0f64, -14.0f64, -3.0f64, + -7.0f64, -11.0f64, -15.0f64, -4.0f64, -8.0f64, -12.0f64, -16.0f64 + ) + ); + } + + #[test] + fn test_mul_scalar() { + let result = Matrix4::new( + 0.5f64, 2.5f64, 4.5f64, 6.5f64, 1.0f64, 3.0f64, 5.0f64, 7.0f64, 1.5f64, 3.5f64, 5.5f64, + 7.5f64, 2.0f64, 4.0f64, 6.0f64, 8.0f64, + ); + assert_eq!(A * F, result); + assert_eq!(F * A, result); + } + + #[test] + fn test_div_scalar() { + assert_eq!( + A / F, + Matrix4::new( + 2.0f64, 10.0f64, 18.0f64, 26.0f64, 4.0f64, 12.0f64, 20.0f64, 28.0f64, 6.0f64, + 14.0f64, 22.0f64, 30.0f64, 8.0f64, 16.0f64, 24.0f64, 32.0f64 + ) + ); + assert_eq!( + 12.0f64 / D, + Matrix4::new( + 3.0f64, 4.0f64, 6.0f64, 12.0f64, 4.0f64, 3.0f64, 4.0f64, 6.0f64, 6.0f64, 4.0f64, + 3.0f64, 4.0f64, 12.0f64, 6.0f64, 4.0f64, 3.0f64 + ) + ); + } + + #[test] + fn test_rem_scalar() { + assert_eq!( + A % 4.0f64, + Matrix4::new( + 1.0f64, 1.0f64, 1.0f64, 1.0f64, 2.0f64, 2.0f64, 2.0f64, 2.0f64, 3.0f64, 3.0f64, + 3.0f64, 3.0f64, 0.0f64, 0.0f64, 0.0f64, 0.0f64 + ) + ); + assert_eq!( + 16.0f64 % A, + Matrix4::new( + 0.0f64, 1.0f64, 7.0f64, 3.0f64, 0.0f64, 4.0f64, 6.0f64, 2.0f64, 1.0f64, 2.0f64, + 5.0f64, 1.0f64, 0.0f64, 0.0f64, 4.0f64, 0.0f64 + ) + ); + } + + #[test] + fn test_add_matrix() { + assert_eq!( + A + B, + Matrix4::new( + 3.0f64, 11.0f64, 19.0f64, 27.0f64, 5.0f64, 13.0f64, 21.0f64, 29.0f64, 7.0f64, + 15.0f64, 23.0f64, 31.0f64, 9.0f64, 17.0f64, 25.0f64, 33.0f64 + ) + ); + } + + #[test] + fn test_sub_matrix() { + assert_eq!( + A - B, + Matrix4::new( + -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, + -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64, -1.0f64 + ) + ); + } + + #[test] + fn test_mul_vector() { + assert_eq!(A * V, Vector4::new(30.0f64, 70.0f64, 110.0f64, 150.0f64)); + } + + #[test] + fn test_mul_matrix() { + assert_eq!( + A * B, + Matrix4::new( + 100.0f64, 228.0f64, 356.0f64, 484.0f64, 110.0f64, 254.0f64, 398.0f64, 542.0f64, + 120.0f64, 280.0f64, 440.0f64, 600.0f64, 130.0f64, 306.0f64, 482.0f64, 658.0f64 + ) + ); + + assert_eq!(A * B, &A * &B); + } + + #[test] + fn test_sum_matrix() { + assert_eq!(A + B + C + D, [A, B, C, D].iter().sum()); + assert_eq!(A + B + C + D, [A, B, C, D].iter().cloned().sum()); + } + + #[test] + fn test_product_matrix() { + assert_eq!(A * B * C * D, [A, B, C, D].iter().product()); + assert_eq!(A * B * C * D, [A, B, C, D].iter().cloned().product()); + } + + #[test] + fn test_determinant() { + assert_eq!(A.determinant(), 0.0f64); + } + + #[test] + fn test_trace() { + assert_eq!(A.trace(), 34.0f64); + } + + #[test] + fn test_transpose() { + assert_eq!( + A.transpose(), + Matrix4::::new( + 1.0f64, 2.0f64, 3.0f64, 4.0f64, 5.0f64, 6.0f64, 7.0f64, 8.0f64, 9.0f64, 10.0f64, + 11.0f64, 12.0f64, 13.0f64, 14.0f64, 15.0f64, 16.0f64 + ) + ); + } + + #[test] + fn test_transpose_self() { + let mut mut_a = A; + mut_a.transpose_self(); + assert_eq!(mut_a, A.transpose()); + } + + #[test] + fn test_invert() { + assert!(Matrix4::::identity().invert().unwrap().is_identity()); + + assert_ulps_eq!( + &C.invert().unwrap(), + &(Matrix4::new( + 5.0f64, -4.0f64, 1.0f64, 0.0f64, -4.0f64, 8.0f64, -4.0f64, 0.0f64, 4.0f64, -8.0f64, + 4.0f64, 8.0f64, -3.0f64, 4.0f64, 1.0f64, -8.0f64 + ) * 0.125f64) + ); + + let mat_c = Matrix4::new( + -0.131917f64, + -0.76871f64, + 0.625846f64, + 0.0f64, + -0., + 0.631364f64, + 0.775487f64, + 0.0f64, + -0.991261f64, + 0.1023f64, + -0.083287f64, + 0.0f64, + 0., + -1.262728f64, + -1.550973f64, + 1.0f64, + ); + assert!((mat_c.invert().unwrap() * mat_c).is_identity()); + + let mat_d = Matrix4::new( + 0.065455f64, + -0.720002f64, + 0.690879f64, + 0.0f64, + -0., + 0.692364f64, + 0.721549f64, + 0.0f64, + -0.997856f64, + -0.047229f64, + 0.045318f64, + 0.0f64, + 0., + -1.384727f64, + -1.443098f64, + 1.0f64, + ); + assert!((mat_d.invert().unwrap() * mat_d).is_identity()); + + let mat_e = Matrix4::new( + 0.409936f64, + 0.683812f64, + -0.603617f64, + 0.0f64, + 0., + 0.661778f64, + 0.7497f64, + 0.0f64, + 0.912114f64, + -0.307329f64, + 0.271286f64, + 0.0f64, + -0., + -1.323555f64, + -1.499401f64, + 1.0f64, + ); + assert!((mat_e.invert().unwrap() * mat_e).is_identity()); + + let mat_f = Matrix4::new( + -0.160691f64, + -0.772608f64, + 0.614211f64, + 0.0f64, + -0., + 0.622298f64, + 0.78278f64, + 0.0f64, + -0.987005f64, + 0.125786f64, + -0.099998f64, + 0.0f64, + 0., + -1.244597f64, + -1.565561f64, + 1.0f64, + ); + assert!((mat_f.invert().unwrap() * mat_f).is_identity()); + } + + #[test] + fn test_predicates() { + assert!(Matrix4::::identity().is_identity()); + assert!(Matrix4::::identity().is_symmetric()); + assert!(Matrix4::::identity().is_diagonal()); + assert!(Matrix4::::identity().is_invertible()); + + assert!(!A.is_identity()); + assert!(!A.is_symmetric()); + assert!(!A.is_diagonal()); + assert!(!A.is_invertible()); + + assert!(!D.is_identity()); + assert!(D.is_symmetric()); + assert!(!D.is_diagonal()); + assert!(D.is_invertible()); + + assert!(Matrix4::from_value(6.0f64).is_diagonal()); + } + + #[test] + fn test_from_translation() { + let mat = Matrix4::from_translation(Vector3::new(1.0f64, 2.0f64, 3.0f64)); + let vertex = Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64); + let res = mat * vertex; + assert_eq!(res, Vector4::new(1., 2., 3., 1.)); + } + + #[test] + fn test_cast() { + assert_ulps_eq!( + Matrix2::new(0.2f64, 1.5, 4.7, 2.3).cast().unwrap(), + Matrix2::new(0.2f32, 1.5, 4.7, 2.3) + ); + assert_ulps_eq!( + Matrix3::new(0.2f64, 1.5, 4.7, 2.3, 5.7, 2.1, 4.6, 5.2, 6.6,) + .cast() + .unwrap(), + Matrix3::new(0.2f32, 1.5, 4.7, 2.3, 5.7, 2.1, 4.6, 5.2, 6.6,) + ); + + assert_ulps_eq!( + Matrix4::new( + 0.2f64, 1.5, 4.7, 2.5, 2.3, 5.7, 2.1, 1.1, 4.6, 5.2, 6.6, 0.2, 3.2, 1.8, 0.4, 2.9, + ) + .cast() + .unwrap(), + Matrix4::new( + 0.2f32, 1.5, 4.7, 2.5, 2.3, 5.7, 2.1, 1.1, 4.6, 5.2, 6.6, 0.2, 3.2, 1.8, 0.4, 2.9, + ) + ); + } + + #[test] + fn test_look_to_rh() { + let eye = Point3::new(10.0, 15.0, 20.0); + let dir = Vector3::new(1.0, 2.0, 3.0).normalize(); + let up = Vector3::unit_y(); + + let m = Matrix4::look_to_rh(eye, dir, up); + #[allow(deprecated)] + { + assert_ulps_eq!(m, Matrix4::look_at_dir(eye, dir, up)); + } + + let expected = Matrix4::from([ + [-0.9486833, -0.16903086, -0.26726127, 0.0], + [0.0, 0.84515435, -0.53452253, 0.0], + [0.31622776, -0.5070926, -0.8017838, 0.0], + [3.1622782, -0.84515476, 26.726126, 1.0_f32] + ]); + assert_ulps_eq!(expected, m); + + let m = Matrix4::look_at_rh(eye, eye + dir, up); + assert_abs_diff_eq!(expected, m, epsilon = 1.0e-4); + } + + #[test] + fn test_look_to_lh() { + let eye = Point3::new(10.0, 15.0, 20.0); + let dir = Vector3::new(1.0, 2.0, 3.0).normalize(); + let up = Vector3::unit_y(); + + let m = Matrix4::look_to_lh(eye, dir, up); + + let expected = Matrix4::from([ + [0.9486833, -0.16903086, 0.26726127, 0.0], + [0.0, 0.84515435, 0.53452253, 0.0], + [-0.31622776, -0.5070926, 0.8017838, 0.0], + [-3.1622782, -0.84515476, -26.726126, 1.0_f32] + ]); + assert_ulps_eq!(expected, m); + + let m = Matrix4::look_at_lh(eye, eye + dir, up); + assert_abs_diff_eq!(expected, m, epsilon = 1.0e-4); + } + + mod from { + use cgmath::*; + + #[test] + fn test_quaternion() { + let quaternion = Quaternion::new(2f32, 3f32, 4f32, 5f32); + + let matrix_short = Matrix4::from(quaternion); + + let matrix_long = Matrix3::from(quaternion); + let matrix_long = Matrix4::from(matrix_long); + + assert_ulps_eq!(matrix_short, matrix_long); + } + } +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/tests/point.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/point.rs new file mode 100644 index 0000000..9344045 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/point.rs @@ -0,0 +1,95 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate approx; +extern crate cgmath; + +use cgmath::*; + +#[test] +fn test_constructor() { + assert_eq!(point1(1f32), Point1::new(1f32)); + assert_eq!(point2(1f32, 2f32), Point2::new(1f32, 2f32)); + assert_eq!(point3(1f64, 2f64, 3f64), Point3::new(1f64, 2f64, 3f64)); +} + +macro_rules! impl_test_mul { + ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // point * scalar ops + assert_eq!($v * $s, $PointN::new($($v.$field * $s),+)); + assert_eq!($s * $v, $PointN::new($($s * $v.$field),+)); + assert_eq!(&$v * $s, $v * $s); + assert_eq!($s * &$v, $s * $v); + // commutativity + assert_eq!($v * $s, $s * $v); + ) +} + +macro_rules! impl_test_div { + ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // point / scalar ops + assert_eq!($v / $s, $PointN::new($($v.$field / $s),+)); + assert_eq!($s / $v, $PointN::new($($s / $v.$field),+)); + assert_eq!(&$v / $s, $v / $s); + assert_eq!($s / &$v, $s / $v); + ) +} + +macro_rules! impl_test_rem { + ($PointN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // point % scalar ops + assert_eq!($v % $s, $PointN::new($($v.$field % $s),+)); + assert_eq!($s % $v, $PointN::new($($s % $v.$field),+)); + assert_eq!(&$v % $s, $v % $s); + assert_eq!($s % &$v, $s % $v); + ) +} + +#[test] +fn test_homogeneous() { + let p = Point3::new(1.0f64, 2.0f64, 3.0f64); + assert_ulps_eq!(&p, &Point3::from_homogeneous(p.to_homogeneous())); +} + +#[test] +fn test_mul() { + impl_test_mul!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); + impl_test_mul!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); +} + +#[test] +fn test_div() { + impl_test_div!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); + impl_test_div!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); +} + +#[test] +fn test_rem() { + impl_test_rem!(Point3 { x, y, z }, 2.0f32, Point3::new(2.0f32, 4.0, 6.0)); + impl_test_rem!(Point2 { x, y }, 2.0f32, Point2::new(2.0f32, 4.0)); +} + +#[test] +fn test_cast() { + assert_ulps_eq!(Point1::new(0.9f64).cast().unwrap(), Point1::new(0.9f32)); + assert_ulps_eq!( + Point2::new(0.9f64, 1.5).cast().unwrap(), + Point2::new(0.9f32, 1.5) + ); + assert_ulps_eq!( + Point3::new(1.0f64, 2.4, -3.13).cast().unwrap(), + Point3::new(1.0f32, 2.4, -3.13) + ); +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/projection.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/projection.rs old mode 100755 new mode 100644 similarity index 100% rename from third_party/cargo/vendor/cgmath-0.17.0/tests/projection.rs rename to third_party/cargo/vendor/cgmath-0.18.0/tests/projection.rs diff --git a/third_party/cargo/vendor/cgmath-0.18.0/tests/quaternion.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/quaternion.rs new file mode 100644 index 0000000..daddb91 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/quaternion.rs @@ -0,0 +1,471 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate approx; +extern crate cgmath; + +macro_rules! impl_test_mul { + ($s:expr, $v:expr) => { + // point * scalar ops + assert_eq!($v * $s, Quaternion::from_sv($v.s * $s, $v.v * $s)); + assert_eq!($s * $v, Quaternion::from_sv($s * $v.s, $s * $v.v)); + assert_eq!(&$v * $s, $v * $s); + assert_eq!($s * &$v, $s * $v); + // commutativity + assert_eq!($v * $s, $s * $v); + }; +} + +macro_rules! impl_test_div { + ($s:expr, $v:expr) => { + // point / scalar ops + assert_eq!($v / $s, Quaternion::from_sv($v.s / $s, $v.v / $s)); + assert_eq!($s / $v, Quaternion::from_sv($s / $v.s, $s / $v.v)); + assert_eq!(&$v / $s, $v / $s); + assert_eq!($s / &$v, $s / $v); + }; +} + +mod operators { + use cgmath::*; + + #[test] + fn test_mul() { + impl_test_mul!( + 2.0f32, + Quaternion::from(Euler { + x: Rad(1f32), + y: Rad(1f32), + z: Rad(1f32), + }) + ); + } + + #[test] + fn test_div() { + impl_test_div!( + 2.0f32, + Quaternion::from(Euler { + x: Rad(1f32), + y: Rad(1f32), + z: Rad(1f32), + }) + ); + } + + #[test] + fn test_iter_sum() { + let q1 = Quaternion::from(Euler { + x: Rad(2f32), + y: Rad(1f32), + z: Rad(1f32), + }); + let q2 = Quaternion::from(Euler { + x: Rad(1f32), + y: Rad(2f32), + z: Rad(1f32), + }); + let q3 = Quaternion::from(Euler { + x: Rad(1f32), + y: Rad(1f32), + z: Rad(2f32), + }); + + assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().sum()); + assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().cloned().sum()); + } + + #[test] + fn test_iter_product() { + let q1 = Quaternion::from(Euler { + x: Rad(2f32), + y: Rad(1f32), + z: Rad(1f32), + }); + let q2 = Quaternion::from(Euler { + x: Rad(1f32), + y: Rad(2f32), + z: Rad(1f32), + }); + let q3 = Quaternion::from(Euler { + x: Rad(1f32), + y: Rad(1f32), + z: Rad(2f32), + }); + + assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().product()); + assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().cloned().product()); + } +} + +mod to_from_euler { + use std::f32; + + use cgmath::*; + + fn check_euler(rotation: Euler>) { + assert_relative_eq!( + Euler::from(Quaternion::from(rotation)), + rotation, + epsilon = 0.001 + ); + } + + const HPI: f32 = f32::consts::FRAC_PI_2; + + #[test] + fn test_zero() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(0f32), + z: Rad(0f32), + }); + } + #[test] + fn test_yaw_pos_1() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(1f32), + z: Rad(0f32), + }); + } + #[test] + fn test_yaw_neg_1() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(-1f32), + z: Rad(0f32), + }); + } + #[test] + fn test_pitch_pos_1() { + check_euler(Euler { + x: Rad(1f32), + y: Rad(0f32), + z: Rad(0f32), + }); + } + #[test] + fn test_pitch_neg_1() { + check_euler(Euler { + x: Rad(-1f32), + y: Rad(0f32), + z: Rad(0f32), + }); + } + #[test] + fn test_roll_pos_1() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(0f32), + z: Rad(1f32), + }); + } + #[test] + fn test_roll_neg_1() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(0f32), + z: Rad(-1f32), + }); + } + #[test] + fn test_pitch_yaw_roll_pos_1() { + check_euler(Euler { + x: Rad(1f32), + y: Rad(1f32), + z: Rad(1f32), + }); + } + #[test] + fn test_pitch_yaw_roll_neg_1() { + check_euler(Euler { + x: Rad(-1f32), + y: Rad(-1f32), + z: Rad(-1f32), + }); + } + #[test] + fn test_pitch_yaw_roll_pos_hp() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(HPI), + z: Rad(1f32), + }); + } + #[test] + fn test_pitch_yaw_roll_neg_hp() { + check_euler(Euler { + x: Rad(0f32), + y: Rad(-HPI), + z: Rad(1f32), + }); + } +} + +mod from { + mod matrix3 { + use cgmath::*; + + fn check_with_euler(x: Rad, y: Rad, z: Rad) { + let matrix3 = Matrix3::from(Euler { x: x, y: y, z: z }); + let quaternion = Quaternion::from(matrix3); + let quaternion_matrix3 = Matrix3::from(quaternion); + assert_ulps_eq!(matrix3, quaternion_matrix3); + } + + // triggers: trace >= S::zero() + #[test] + fn test_positive_trace() { + check_with_euler(Rad(0.0f32), Rad(0.0), Rad(0.0f32)); + } + + // triggers: (mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2]) + #[test] + fn test_xx_maximum() { + check_with_euler(Rad(2.0f32), Rad(1.0), Rad(-1.2f32)); + } + + // triggers: mat[1][1] > mat[2][2] + #[test] + fn test_yy_maximum() { + check_with_euler(Rad(2.0f32), Rad(1.0), Rad(3.0f32)); + } + + // base case + #[test] + fn test_zz_maximum() { + check_with_euler(Rad(1.0f32), Rad(1.0), Rad(3.0f32)); + } + } +} + +mod arc { + use cgmath::*; + + #[inline] + fn test(src: Vector3, dst: Vector3) { + let q = Quaternion::from_arc(src, dst, None); + let v = q.rotate_vector(src); + assert_ulps_eq!(v.normalize(), dst.normalize()); + } + + #[test] + fn test_same() { + let v = Vector3::unit_x(); + let q = Quaternion::from_arc(v, v, None); + assert_eq!(q, Quaternion::new(1.0, 0.0, 0.0, 0.0)); + } + + #[test] + fn test_opposite() { + let v = Vector3::unit_x(); + test(v, -v); + } + + #[test] + fn test_random() { + test(vec3(1.0, 2.0, 3.0), vec3(-4.0, 5.0, -6.0)); + } + + #[test] + fn test_ortho() { + let q: Quaternion = Quaternion::from_arc(Vector3::unit_x(), Vector3::unit_y(), None); + let q2 = Quaternion::from_axis_angle(Vector3::unit_z(), Rad::turn_div_4()); + assert_ulps_eq!(q, q2); + } +} + +mod rotate_from_euler { + use cgmath::*; + + #[test] + fn test_x() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Quaternion::from(Euler::new(Deg(90.0), Deg(0.0), Deg(0.0))); + assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); + + let rot = Quaternion::from(Euler::new(Deg(-90.0), Deg(0.0), Deg(0.0))); + assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); + } + + #[test] + fn test_y() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(90.0), Deg(0.0))); + assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); + + let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(-90.0), Deg(0.0))); + assert_ulps_eq!(vec3(-1.0, 0.0, 0.0), rot * vec); + } + + #[test] + fn test_z() { + let vec = vec3(1.0, 0.0, 0.0); + + let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(0.0), Deg(90.0))); + assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); + + let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(0.0), Deg(-90.0))); + assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); + } + + // tests that the Y rotation is done after the X + #[test] + fn test_x_then_y() { + let vec = vec3(0.0, 1.0, 0.0); + + let rot = Quaternion::from(Euler::new(Deg(90.0), Deg(90.0), Deg(0.0))); + assert_ulps_eq!(vec3(0.0f32, 0.0f32, 1.0f32), rot * vec); + } + + // tests that the Z rotation is done after the Y + #[test] + fn test_y_then_z() { + let vec = vec3(0.0f32, 0.0f32, 1.0f32); + + let rot = Quaternion::from(Euler::new(Deg(0.0), Deg(90.0), Deg(90.0))); + assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); + } +} + +mod rotate_from_axis_angle { + use cgmath::*; + + #[test] + fn test_x() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Quaternion::from_angle_x(Deg(90.0)); + assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); + } + + #[test] + fn test_y() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Quaternion::from_angle_y(Deg(90.0)); + assert_ulps_eq!(vec3(1.0, 0.0, 0.0), rot * vec); + } + + #[test] + fn test_z() { + let vec = vec3(1.0, 0.0, 0.0); + + let rot = Quaternion::from_angle_z(Deg(90.0)); + assert_ulps_eq!(vec3(0.0, 1.0, 0.0), rot * vec); + } + + #[test] + fn test_xy() { + let vec = vec3(0.0, 0.0, 1.0); + + let rot = Quaternion::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), Deg(90.0)); + assert_ulps_eq!( + vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0), + rot * vec + ); + } + + #[test] + fn test_yz() { + let vec = vec3(1.0, 0.0, 0.0); + + let rot = Quaternion::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), Deg(-90.0)); + assert_ulps_eq!( + vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0), + rot * vec + ); + } + + #[test] + fn test_xz() { + let vec = vec3(0.0, 1.0, 0.0); + + let rot = Quaternion::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), Deg(90.0)); + assert_ulps_eq!( + vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), + rot * vec + ); + } +} + +mod rotate_between_vectors { + use cgmath::*; + + #[test] + fn test_around_z_0() { + let expected = Quaternion::new(1.0, 0.0, 0.0, 0.0); + + let a = vec3(12.0, 0.0, 0.0); + let b = vec3(1.0, 0.0, 0.0); + + assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); + } + + #[test] + fn test_around_z_90_cw() { + let expected = Quaternion::new(0.5_f32.sqrt(), 0.0, 0.0, 0.5_f32.sqrt()); + + let a = vec3(8.0, 0.0, 0.0); + let b = vec3(0.0, 9.0, 0.0); + + assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); + } + + #[test] + fn test_around_z_90_ccw() { + let expected = Quaternion::new(0.5_f32.sqrt(), 0.0, 0.0, -0.5_f32.sqrt()); + + let a = vec3(-26.0, 0.0, 0.0); + let b = vec3(0.0, 10.0, 0.0); + + assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); + } + + #[test] + fn test_around_z_180_cw() { + let expected = Quaternion::new(0.0, 0.0, 0.0, 1.0); + + let a = vec3(10.0, 0.0, 0.0); + let b = vec3(-5.0, 0.0, 0.0); + + assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); + } + + #[test] + fn test_around_z_180_ccw() { + let expected = Quaternion::new(0.0, 0.0, 0.0, -1.0); + + let a = vec3(-3.0, 0.0, 0.0); + let b = vec3(40.0, 0.0, 0.0); + + assert_ulps_eq!(Quaternion::between_vectors(a, b), expected); + } +} + +mod cast { + use cgmath::*; + + #[test] + fn test_cast() { + assert_ulps_eq!( + Quaternion::new(0.9f64, 1.5, 2.4, 7.6).cast().unwrap(), + Quaternion::new(0.9f32, 1.5, 2.4, 7.6) + ); + } +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/tests/rotation.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/rotation.rs new file mode 100644 index 0000000..65915c6 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/rotation.rs @@ -0,0 +1,47 @@ +// Copyright 2015 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate cgmath; + +use cgmath::*; + +mod rotation { + use super::cgmath::*; + + pub fn a2>() -> R { + Rotation2::from_angle(Deg(30.0)) + } + + pub fn a3>() -> R { + let axis = Vector3::new(1.0, 1.0, 0.0).normalize(); + Rotation3::from_axis_angle(axis, Deg(30.0)) + } +} + +#[test] +fn test_invert_basis2() { + let a: Basis2<_> = rotation::a2(); + let a = a * a.invert(); + let a: &Matrix2<_> = a.as_ref(); + assert!(a.is_identity()); +} + +#[test] +fn test_invert_basis3() { + let a: Basis3<_> = rotation::a3(); + let a = a * a.invert(); + let a: &Matrix3<_> = a.as_ref(); + assert!(a.is_identity()); +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/swizzle.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/swizzle.rs old mode 100755 new mode 100644 similarity index 100% rename from third_party/cargo/vendor/cgmath-0.17.0/tests/swizzle.rs rename to third_party/cargo/vendor/cgmath-0.18.0/tests/swizzle.rs diff --git a/third_party/cargo/vendor/cgmath-0.18.0/tests/transform.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/transform.rs new file mode 100644 index 0000000..926ff83 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/transform.rs @@ -0,0 +1,157 @@ +// Copyright 2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate approx; +extern crate cgmath; + +#[cfg(feature = "serde")] +extern crate serde_json; + +use cgmath::*; + +#[test] +fn test_mul() { + let t1 = Decomposed { + scale: 2.0f64, + rot: Quaternion::new(0.5f64.sqrt(), 0.5f64.sqrt(), 0.0, 0.0), + disp: Vector3::new(1.0f64, 2.0, 3.0), + }; + let t2 = Decomposed { + scale: 3.0f64, + rot: Quaternion::new(0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), 0.0), + disp: Vector3::new(-2.0, 1.0, 0.0), + }; + + let actual = t1 * t2; + + let expected = Decomposed { + scale: 6.0f64, + rot: Quaternion::new(0.5, 0.5, 0.5, 0.5), + disp: Vector3::new(-3.0, 2.0, 5.0), + }; + + assert_ulps_eq!(actual, expected); +} + +#[test] +fn test_mul_one() { + let t = Decomposed { + scale: 2.0f64, + rot: Quaternion::new(0.5f64.sqrt(), 0.5f64.sqrt(), 0.0, 0.0), + disp: Vector3::new(1.0f64, 2.0, 3.0), + }; + let one = Decomposed::one(); + + assert_ulps_eq!(t * one, t); + assert_ulps_eq!(one * t, t); +} + +#[test] +fn test_invert() { + let v = Vector3::new(1.0f64, 2.0, 3.0); + let t = Decomposed { + scale: 1.5f64, + rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), + disp: Vector3::new(6.0f64, -7.0, 8.0), + }; + let ti = t + .inverse_transform() + .expect("Expected successful inversion"); + let vt = t.transform_vector(v); + assert_ulps_eq!(&v, &ti.transform_vector(vt)); +} + +#[test] +fn test_inverse_vector() { + let v = Vector3::new(1.0f64, 2.0, 3.0); + let t = Decomposed { + scale: 1.5f64, + rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), + disp: Vector3::new(6.0f64, -7.0, 8.0), + }; + let vt = t + .inverse_transform_vector(v) + .expect("Expected successful inversion"); + assert_ulps_eq!(v, t.transform_vector(vt)); +} + +#[test] +#[allow(deprecated)] +fn test_look_at() { + let eye = Point3::new(0.0f64, 0.0, -5.0); + let center = Point3::new(0.0f64, 0.0, 0.0); + let up = Vector3::new(1.0f64, 0.0, 0.0); + let t: Decomposed, Quaternion> = Transform::look_at(eye, center, up); + assert_ulps_eq!(t, Decomposed::, Quaternion>::look_at(eye, center, up)); + let point = Point3::new(1.0f64, 0.0, 0.0); + let view_point = Point3::new(0.0f64, 1.0, 5.0); + assert_ulps_eq!(&t.transform_point(point), &view_point); +} + +#[test] +fn test_look_at_lh() { + let eye = Point3::new(0.0f64, 0.0, -5.0); + let center = Point3::new(0.0f64, 0.0, 0.0); + let up = Vector3::new(1.0f64, 0.0, 0.0); + let t: Decomposed, Quaternion> = Transform::look_at_lh(eye, center, up); + assert_ulps_eq!(t, Decomposed::, Quaternion>::look_at_lh(eye, center, up)); + let point = Point3::new(1.0f64, 0.0, 0.0); + let view_point = Point3::new(0.0f64, 1.0, 5.0); + assert_ulps_eq!(&t.transform_point(point), &view_point); + + // Decomposed::look_at_lh and Matrix4::look_at_lh should be consistent + let t: Matrix4 = Transform::look_at_lh(eye, center, up); + assert_ulps_eq!(t, Matrix4::::look_at_lh(eye, center, up)); + assert_ulps_eq!(&t.transform_point(point), &view_point); + + // Decomposed::look_at is inconsistent and deprecated, but verify that the behvaior + // remains the same until removed. + #[allow(deprecated)] + let t: Decomposed, Quaternion> = Transform::look_at(eye, center, up); + assert_ulps_eq!(&t.transform_point(point), &view_point); +} + +#[test] +fn test_look_at_rh() { + let eye = Point3::new(0.0f64, 0.0, -5.0); + let center = Point3::new(0.0f64, 0.0, 0.0); + let up = Vector3::new(1.0f64, 0.0, 0.0); + let t: Decomposed, Quaternion> = Transform::look_at_rh(eye, center, up); + assert_ulps_eq!(t, Decomposed::, Quaternion>::look_at_rh(eye, center, up)); + let point = Point3::new(1.0f64, 0.0, 0.0); + let view_point = Point3::new(0.0f64, 1.0, -5.0); + assert_ulps_eq!(&t.transform_point(point), &view_point); + + // Decomposed::look_at_rh and Matrix4::look_at_rh should be consistent + let t: Matrix4 = Transform::look_at_rh(eye, center, up); + assert_ulps_eq!(t, Matrix4::::look_at_rh(eye, center, up)); + assert_ulps_eq!(&t.transform_point(point), &view_point); +} + +#[cfg(feature = "serde")] +#[test] +fn test_serialize() { + let t = Decomposed { + scale: 1.5f64, + rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), + disp: Vector3::new(6.0f64, -7.0, 8.0), + }; + + let serialized = serde_json::to_string(&t).unwrap(); + let deserialized: Decomposed, Quaternion> = + serde_json::from_str(&serialized).unwrap(); + + assert_ulps_eq!(&t, &deserialized); +} diff --git a/third_party/cargo/vendor/cgmath-0.18.0/tests/vector.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/vector.rs new file mode 100644 index 0000000..e602932 --- /dev/null +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/vector.rs @@ -0,0 +1,352 @@ +// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, +// refer to the Cargo.toml file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate approx; +extern crate cgmath; + +use cgmath::*; +use std::f64; +use std::iter; + +#[test] +fn test_constructor() { + assert_eq!(vec1(1f32), Vector1::new(1f32)); + assert_eq!(vec2(1f32, 2f32), Vector2::new(1f32, 2f32)); + assert_eq!(vec3(1f64, 2f64, 3f64), Vector3::new(1f64, 2f64, 3f64)); + assert_eq!( + vec4(1isize, 2isize, 3isize, 4isize), + Vector4::new(1isize, 2isize, 3isize, 4isize) + ); +} + +#[test] +fn test_from_value() { + assert_eq!( + Vector2::from_value(102isize), + Vector2::new(102isize, 102isize) + ); + assert_eq!( + Vector3::from_value(22isize), + Vector3::new(22isize, 22isize, 22isize) + ); + assert_eq!( + Vector4::from_value(76.5f64), + Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64) + ); +} + +macro_rules! impl_test_add { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector + vector ops + assert_eq!($v + $v, $VectorN::new($($v.$field + $v.$field),+)); + assert_eq!(&$v + &$v, $v + $v); + assert_eq!(&$v + $v, $v + $v); + assert_eq!($v + &$v, $v + $v); + ) +} + +macro_rules! impl_test_sub { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector - vector ops + assert_eq!($v - $v, $VectorN::new($($v.$field - $v.$field),+)); + assert_eq!(&$v - &$v, $v - $v); + assert_eq!(&$v - $v, $v - $v); + assert_eq!($v - &$v, $v - $v); + ) +} + +macro_rules! impl_test_mul { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector * scalar ops + assert_eq!($v * $s, $VectorN::new($($v.$field * $s),+)); + assert_eq!($s * $v, $VectorN::new($($s * $v.$field),+)); + assert_eq!(&$v * $s, $v * $s); + assert_eq!($s * &$v, $s * $v); + // commutativity + assert_eq!($v * $s, $s * $v); + ) +} + +macro_rules! impl_test_div { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector / scalar ops + assert_eq!($v / $s, $VectorN::new($($v.$field / $s),+)); + assert_eq!($s / $v, $VectorN::new($($s / $v.$field),+)); + assert_eq!(&$v / $s, $v / $s); + assert_eq!($s / &$v, $s / $v); + ) +} + +macro_rules! impl_test_rem { + ($VectorN:ident { $($field:ident),+ }, $s:expr, $v:expr) => ( + // vector % scalar ops + assert_eq!($v % $s, $VectorN::new($($v.$field % $s),+)); + assert_eq!($s % $v, $VectorN::new($($s % $v.$field),+)); + assert_eq!(&$v % $s, $v % $s); + assert_eq!($s % &$v, $s % $v); + ) +} + +macro_rules! impl_test_iter_sum { + ($VectorN:ident { $($field:ident),+ }, $ty:ty, $s:expr, $v:expr) => ( + assert_eq!($VectorN::new($($v.$field * $s),+), + iter::repeat($v).take($s as usize).sum()); + ) +} + +#[test] +fn test_add() { + impl_test_add!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_add!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_add!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} + +#[test] +fn test_sub() { + impl_test_sub!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_sub!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_sub!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} + +#[test] +fn test_mul() { + impl_test_mul!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_mul!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_mul!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} + +#[test] +fn test_div() { + impl_test_div!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_div!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_div!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} + +#[test] +fn test_rem() { + impl_test_rem!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); + impl_test_rem!(Vector3 { x, y, z }, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_rem!(Vector2 { x, y }, 2.0f32, vec2(2.0f32, 4.0)); +} + +#[test] +fn test_dot() { + assert_eq!(Vector2::new(1.0, 2.0).dot(Vector2::new(3.0, 4.0)), 11.0); + assert_eq!( + Vector3::new(1.0, 2.0, 3.0).dot(Vector3::new(4.0, 5.0, 6.0)), + 32.0 + ); + assert_eq!( + Vector4::new(1.0, 2.0, 3.0, 4.0).dot(Vector4::new(5.0, 6.0, 7.0, 8.0)), + 70.0 + ); +} + +#[test] +fn test_sum() { + assert_eq!(Vector2::new(1isize, 2isize).sum(), 3isize); + assert_eq!(Vector3::new(1isize, 2isize, 3isize).sum(), 6isize); + assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).sum(), 10isize); + + assert_eq!(Vector2::new(3.0f64, 4.0f64).sum(), 7.0f64); + assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).sum(), 15.0f64); + assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).sum(), 26.0f64); +} + +#[test] +fn test_iter_sum() { + impl_test_iter_sum!( + Vector4 { x, y, z, w }, + f32, + 2.0f32, + vec4(2.0f32, 4.0, 6.0, 8.0) + ); + impl_test_iter_sum!(Vector3 { x, y, z }, f32, 2.0f32, vec3(2.0f32, 4.0, 6.0)); + impl_test_iter_sum!(Vector2 { x, y }, f32, 2.0f32, vec2(2.0f32, 4.0)); + + impl_test_iter_sum!(Vector4 { x, y, z, w }, usize, 2usize, vec4(2usize, 4, 6, 8)); + impl_test_iter_sum!(Vector3 { x, y, z }, usize, 2usize, vec3(2usize, 4, 6)); + impl_test_iter_sum!(Vector2 { x, y }, usize, 2usize, vec2(2usize, 4)); +} + +#[test] +fn test_product() { + assert_eq!(Vector2::new(1isize, 2isize).product(), 2isize); + assert_eq!(Vector3::new(1isize, 2isize, 3isize).product(), 6isize); + assert_eq!( + Vector4::new(1isize, 2isize, 3isize, 4isize).product(), + 24isize + ); + + assert_eq!(Vector2::new(3.0f64, 4.0f64).product(), 12.0f64); + assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).product(), 120.0f64); + assert_eq!( + Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).product(), + 1680.0f64 + ); +} + +#[test] +fn test_cross() { + let a = Vector3::new(1isize, 2isize, 3isize); + let b = Vector3::new(4isize, 5isize, 6isize); + let r = Vector3::new(-3isize, 6isize, -3isize); + assert_eq!(a.cross(b), r); +} + +#[test] +fn test_is_perpendicular() { + assert!(Vector2::new(1.0f64, 0.0f64).is_perpendicular(Vector2::new(0.0f64, 1.0f64))); + assert!( + Vector3::new(0.0f64, 1.0f64, 0.0f64).is_perpendicular(Vector3::new(0.0f64, 0.0f64, 1.0f64)) + ); + assert!(Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64) + .is_perpendicular(Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64))); +} + +#[cfg(test)] +mod test_magnitude { + use cgmath::*; + + #[test] + fn test_vector2() { + let (a, a_res) = (Vector2::new(3.0f64, 4.0f64), 5.0f64); // (3, 4, 5) Pythagorean triple + let (b, b_res) = (Vector2::new(5.0f64, 12.0f64), 13.0f64); // (5, 12, 13) Pythagorean triple + + assert_eq!(a.magnitude2(), a_res * a_res); + assert_eq!(b.magnitude2(), b_res * b_res); + + assert_eq!(a.magnitude(), a_res); + assert_eq!(b.magnitude(), b_res); + } + + #[test] + fn test_vector3() { + let (a, a_res) = (Vector3::new(2.0f64, 3.0f64, 6.0f64), 7.0f64); // (2, 3, 6, 7) Pythagorean quadruple + let (b, b_res) = (Vector3::new(1.0f64, 4.0f64, 8.0f64), 9.0f64); // (1, 4, 8, 9) Pythagorean quadruple + + assert_eq!(a.magnitude2(), a_res * a_res); + assert_eq!(b.magnitude2(), b_res * b_res); + + assert_eq!(a.magnitude(), a_res); + assert_eq!(b.magnitude(), b_res); + } + + #[test] + fn test_vector4() { + let (a, a_res) = (Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64), 11.0f64); // (1, 2, 4, 10, 11) Pythagorean quintuple + let (b, b_res) = (Vector4::new(1.0f64, 2.0f64, 8.0f64, 10.0f64), 13.0f64); // (1, 2, 8, 10, 13) Pythagorean quintuple + + assert_eq!(a.magnitude2(), a_res * a_res); + assert_eq!(b.magnitude2(), b_res * b_res); + + assert_eq!(a.magnitude(), a_res); + assert_eq!(b.magnitude(), b_res); + } +} + +#[test] +fn test_angle() { + assert_ulps_eq!( + Vector2::new(1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)), + &Rad(f64::consts::FRAC_PI_2) + ); + assert_ulps_eq!( + Vector2::new(10.0f64, 0.0f64).angle(Vector2::new(0.0f64, 5.0f64)), + &Rad(f64::consts::FRAC_PI_2) + ); + assert_ulps_eq!( + Vector2::new(-1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)), + &-Rad(f64::consts::FRAC_PI_2) + ); + + assert_ulps_eq!( + Vector3::new(1.0f64, 0.0f64, 1.0f64).angle(Vector3::new(1.0f64, 1.0f64, 0.0f64)), + &Rad(f64::consts::FRAC_PI_3) + ); + assert_ulps_eq!( + Vector3::new(10.0f64, 0.0f64, 10.0f64).angle(Vector3::new(5.0f64, 5.0f64, 0.0f64)), + &Rad(f64::consts::FRAC_PI_3) + ); + assert_ulps_eq!( + Vector3::new(-1.0f64, 0.0f64, -1.0f64).angle(Vector3::new(1.0f64, -1.0f64, 0.0f64)), + &Rad(2.0f64 * f64::consts::FRAC_PI_3) + ); + + assert_ulps_eq!( + Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64) + .angle(Vector4::new(0.0f64, 1.0f64, 0.0f64, 1.0f64)), + &Rad(f64::consts::FRAC_PI_2) + ); + assert_ulps_eq!( + Vector4::new(10.0f64, 0.0f64, 10.0f64, 0.0f64) + .angle(Vector4::new(0.0f64, 5.0f64, 0.0f64, 5.0f64)), + &Rad(f64::consts::FRAC_PI_2) + ); + assert_ulps_eq!( + Vector4::new(-1.0f64, 0.0f64, -1.0f64, 0.0f64) + .angle(Vector4::new(0.0f64, 1.0f64, 0.0f64, 1.0f64)), + &Rad(f64::consts::FRAC_PI_2) + ); +} + +#[test] +fn test_normalize() { + // TODO: test normalize_to, normalize_sel.0, and normalize_self_to + assert_ulps_eq!( + Vector2::new(3.0f64, 4.0f64).normalize(), + &Vector2::new(3.0 / 5.0, 4.0 / 5.0) + ); + assert_ulps_eq!( + Vector3::new(2.0f64, 3.0f64, 6.0f64).normalize(), + &Vector3::new(2.0 / 7.0, 3.0 / 7.0, 6.0 / 7.0) + ); + assert_ulps_eq!( + Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64).normalize(), + &Vector4::new(1.0 / 11.0, 2.0 / 11.0, 4.0 / 11.0, 10.0 / 11.0) + ); +} + +#[test] +fn test_project_on() { + assert_ulps_eq!( + Vector2::new(-1.0f64, 5.0).project_on(Vector2::new(2.0, 4.0)), + &Vector2::new(9.0 / 5.0, 18.0 / 5.0) + ); + assert_ulps_eq!( + Vector3::new(5.0f64, 6.0, 7.0).project_on(Vector3::new(1.0, 1.0, 1.0)), + &Vector3::new(6.0, 6.0, 6.0) + ); + assert_ulps_eq!( + Vector4::new(0.0f64, -5.0, 5.0, 5.0).project_on(Vector4::new(0.0, 1.0, 0.0, 0.5)), + &Vector4::new(0.0, -2.0, 0.0, -1.0) + ); +} + +#[test] +fn test_cast() { + assert_ulps_eq!( + Vector2::new(0.9f64, 1.5).cast().unwrap(), + Vector2::new(0.9f32, 1.5) + ); + assert_ulps_eq!( + Vector3::new(1.0f64, 2.4, -3.13).cast().unwrap(), + Vector3::new(1.0f32, 2.4, -3.13) + ); + assert_ulps_eq!( + Vector4::new(13.5f64, -4.6, -8.3, 2.41).cast().unwrap(), + Vector4::new(13.5f32, -4.6, -8.3, 2.41) + ); +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/tests/vector4f32.rs b/third_party/cargo/vendor/cgmath-0.18.0/tests/vector4f32.rs old mode 100755 new mode 100644 similarity index 87% rename from third_party/cargo/vendor/cgmath-0.17.0/tests/vector4f32.rs rename to third_party/cargo/vendor/cgmath-0.18.0/tests/vector4f32.rs index 3a9a02f..ad746c5 --- a/third_party/cargo/vendor/cgmath-0.17.0/tests/vector4f32.rs +++ b/third_party/cargo/vendor/cgmath-0.18.0/tests/vector4f32.rs @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[macro_use] extern crate approx; extern crate cgmath; @@ -136,12 +135,8 @@ fn test_rem() { #[test] fn test_dot() { assert_eq!( - Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32).dot(Vector4::new( - 5.0f32, - 6.0f32, - 7.0f32, - 8.0f32 - )), + Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32) + .dot(Vector4::new(5.0f32, 6.0f32, 7.0f32, 8.0f32)), 70.0f32 ); } @@ -165,14 +160,8 @@ fn test_product() { #[test] fn test_is_perpendicular() { - assert!( - Vector4::new(1.0f32, 0.0f32, 0.0f32, 0.0f32).is_perpendicular(Vector4::new( - 0.0f32, - 0.0f32, - 0.0f32, - 1.0f32 - )) - ); + assert!(Vector4::new(1.0f32, 0.0f32, 0.0f32, 0.0f32) + .is_perpendicular(Vector4::new(0.0f32, 0.0f32, 0.0f32, 1.0f32))); } #[cfg(test)] @@ -211,30 +200,18 @@ mod test_magnitude { #[test] fn test_angle() { assert_ulps_eq!( - Vector4::new(1.0f32, 0.0f32, 1.0f32, 0.0f32).angle(Vector4::new( - 0.0f32, - 1.0f32, - 0.0f32, - 1.0f32 - )), + Vector4::new(1.0f32, 0.0f32, 1.0f32, 0.0f32) + .angle(Vector4::new(0.0f32, 1.0f32, 0.0f32, 1.0f32)), &Rad(f32::consts::FRAC_PI_2) ); assert_ulps_eq!( - Vector4::new(10.0f32, 0.0f32, 10.0f32, 0.0f32).angle(Vector4::new( - 0.0f32, - 5.0f32, - 0.0f32, - 5.0f32 - )), + Vector4::new(10.0f32, 0.0f32, 10.0f32, 0.0f32) + .angle(Vector4::new(0.0f32, 5.0f32, 0.0f32, 5.0f32)), &Rad(f32::consts::FRAC_PI_2) ); assert_ulps_eq!( - Vector4::new(-1.0f32, 0.0f32, -1.0f32, 0.0f32).angle(Vector4::new( - 0.0f32, - 1.0f32, - 0.0f32, - 1.0f32 - )), + Vector4::new(-1.0f32, 0.0f32, -1.0f32, 0.0f32) + .angle(Vector4::new(0.0f32, 1.0f32, 0.0f32, 1.0f32)), &Rad(f32::consts::FRAC_PI_2) ); } diff --git a/third_party/cargo/vendor/cloudabi-0.0.3/.cargo-checksum.json b/third_party/cargo/vendor/cloudabi-0.0.3/.cargo-checksum.json deleted file mode 100644 index f79ba65..0000000 --- a/third_party/cargo/vendor/cloudabi-0.0.3/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"16ef935056e2aaf48b28c1340a63cc75febaabc901c752da9a3a2edbe081b429","bitflags.rs":"4621173dcf1307094cf240d26955b6f25c2f770dfd4e975ec2728771209006b5","cloudabi.rs":"93e139ba72a04db4934b04a6f21b054757a218a687e0bd2f6ba32514ec8c5f38"},"package":"ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cloudabi-0.0.3/BUILD.bazel b/third_party/cargo/vendor/cloudabi-0.0.3/BUILD.bazel deleted file mode 100644 index 2a93a24..0000000 --- a/third_party/cargo/vendor/cloudabi-0.0.3/BUILD.bazel +++ /dev/null @@ -1,56 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "restricted", # BSD-2-Clause from expression "BSD-2-Clause" -]) - -# Generated Targets - -rust_library( - name = "cloudabi", - srcs = glob(["**/*.rs"]), - crate_features = [ - "bitflags", - "default", - ], - crate_root = "cloudabi.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.0.3", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", - ], -) diff --git a/third_party/cargo/vendor/cloudabi-0.0.3/Cargo.toml b/third_party/cargo/vendor/cloudabi-0.0.3/Cargo.toml deleted file mode 100644 index ed0daf9..0000000 --- a/third_party/cargo/vendor/cloudabi-0.0.3/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "cloudabi" -version = "0.0.3" -authors = ["Nuxi (https://nuxi.nl/) and contributors"] -description = "Low level interface to CloudABI. Contains all syscalls and related types." -homepage = "https://nuxi.nl/cloudabi/" -documentation = "https://docs.rs/cloudabi/" -keywords = ["cloudabi"] -license = "BSD-2-Clause" -repository = "https://github.com/nuxinl/cloudabi" - -[lib] -path = "cloudabi.rs" -[dependencies.bitflags] -version = "1.0" -optional = true - -[features] -default = ["bitflags"] diff --git a/third_party/cargo/vendor/cloudabi-0.0.3/bitflags.rs b/third_party/cargo/vendor/cloudabi-0.0.3/bitflags.rs deleted file mode 100644 index f764cc1..0000000 --- a/third_party/cargo/vendor/cloudabi-0.0.3/bitflags.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. - -// Appease Rust's tidy. -// ignore-license - -#[cfg(feature = "bitflags")] -#[macro_use] -extern crate bitflags; - -// Minimal implementation of bitflags! in case we can't depend on the bitflags -// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't -// actually truncate. -#[cfg(not(feature = "bitflags"))] -macro_rules! bitflags { - ( - $(#[$attr:meta])* - pub struct $name:ident: $type:ty { - $($(#[$const_attr:meta])* const $const:ident = $val:expr;)* - } - ) => { - $(#[$attr])* - #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] - pub struct $name { bits: $type } - impl $name { - $($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)* - pub fn bits(&self) -> $type { self.bits } - pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } } - } - } -} diff --git a/third_party/cargo/vendor/cloudabi-0.0.3/cloudabi.rs b/third_party/cargo/vendor/cloudabi-0.0.3/cloudabi.rs deleted file mode 100644 index 2909db5..0000000 --- a/third_party/cargo/vendor/cloudabi-0.0.3/cloudabi.rs +++ /dev/null @@ -1,2847 +0,0 @@ -// Copyright (c) 2016-2017 Nuxi (https://nuxi.nl/) and contributors. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -// SUCH DAMAGE. -// -// This file is automatically generated. Do not edit. -// -// Source: https://github.com/NuxiNL/cloudabi - -// Appease Rust's tidy. -// ignore-license -// ignore-tidy-linelength - -//! **PLEASE NOTE: This entire crate including this -//! documentation is automatically generated from -//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt)** -//! -//! # Nuxi CloudABI -//! -//! CloudABI is what you get if you take POSIX, add capability-based -//! security, and remove everything that's incompatible with that. The -//! result is a minimal ABI consisting of only 49 syscalls. -//! -//! CloudABI doesn't have its own kernel, but instead is implemented in existing -//! kernels: FreeBSD has CloudABI support for x86-64 and arm64, and [a patch-set -//! for NetBSD](https://github.com/NuxiNL/netbsd) and [a patch-set for -//! Linux](https://github.com/NuxiNL/linux) are available as well. This means that -//! CloudABI binaries can be executed on different operating systems, without any -//! modification. -//! -//! ## Capability-Based Security -//! -//! Capability-based security means that processes can only perform -//! actions that have no global impact. Processes cannot open files by -//! their absolute path, cannot open network connections, and cannot -//! observe global system state such as the process table. -//! -//! The capabilities of a process are fully determined by its set of open -//! file descriptors (fds). For example, files can only be opened if the -//! process already has a file descriptor to a directory the file is in. -//! -//! Unlike in POSIX, where processes are normally started with file -//! descriptors 0, 1, and 2 reserved for standard input, output, and -//! error, CloudABI does not reserve any file descriptor numbers for -//! specific purposes. -//! -//! In CloudABI, a process depends on its parent process to launch it with -//! the right set of resources, since the process will not be able to open -//! any new resources. For example, a simple static web server would need -//! to be started with a file descriptor to a [TCP -//! listener](https://github.com/NuxiNL/flower), and a file descriptor to -//! the directory for which to serve files. The web server will then be -//! unable to do anything other than reading files in that directory, and -//! process incoming network connections. -//! -//! So, unknown CloudABI binaries can safely be executed without the need -//! for containers, virtual machines, or other sandboxing technologies. -//! -//! Watch [Ed Schouten's Talk at -//! 32C3](https://www.youtube.com/watch?v=3N29vrPoDv8) for more -//! information about what capability-based security for UNIX means. -//! -//! ## Cloudlibc -//! -//! [Cloudlibc](https://github.com/NuxiNL/cloudlibc) is an implementation -//! of the C standard library, without all CloudABI-incompatible -//! functions. For example, Cloudlibc does not have `printf`, but does -//! have `fprintf`. It does not have `open`, but does have `openat`. -//! -//! ## CloudABI-Ports -//! -//! [CloudABI-Ports](https://github.com/NuxiNL/cloudabi-ports) is a -//! collection of ports of commonly used libraries and applications to -//! CloudABI. It contains software such as `zlib`, `libpng`, `boost`, -//! `memcached`, and much more. The software is patched to not depend on -//! any global state, such as files in `/etc` or `/dev`, using `open()`, -//! etc. -//! -//! ## Using CloudABI -//! -//! Instructions for using CloudABI (including kernel modules/patches, -//! toolchain, and ports) are available for several operating systems: -//! -//! - [Arch Linux](https://nuxi.nl/cloudabi/archlinux/) -//! - [Debian, Ubuntu, and other Debian derivatives](https://nuxi.nl/cloudabi/debian/) -//! - [FreeBSD, PC-BSD and DragonFly BSD](https://nuxi.nl/cloudabi/freebsd/) -//! - [Mac OS X](https://nuxi.nl/cloudabi/mac/) -//! - [NetBSD](https://nuxi.nl/cloudabi/netbsd/) -//! -//! ## Specification of the ABI -//! -//! The entire ABI is specified in a a file called -//! [`cloudabi.txt`](https://github.com/NuxiNL/cloudabi/blob/master/cloudabi.txt), -//! from which all -//! [headers](https://github.com/NuxiNL/cloudabi/tree/master/headers) -//! and documentation (including the one you're reading now) is generated. - -#![no_std] -#![allow(non_camel_case_types)] - -include!("bitflags.rs"); - -/// File or memory access pattern advisory information. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum advice { - /// The application expects that it will not access the - /// specified data in the near future. - DONTNEED = 1, - /// The application expects to access the specified data - /// once and then not reuse it thereafter. - NOREUSE = 2, - /// The application has no advice to give on its behavior - /// with respect to the specified data. - NORMAL = 3, - /// The application expects to access the specified data - /// in a random order. - RANDOM = 4, - /// The application expects to access the specified data - /// sequentially from lower offsets to higher offsets. - SEQUENTIAL = 5, - /// The application expects to access the specified data - /// in the near future. - WILLNEED = 6, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, -} - -/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html). -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum auxtype { - /// Base address of the binary argument data provided to - /// [`proc_exec()`](fn.proc_exec.html). - ARGDATA = 256, - /// Length of the binary argument data provided to - /// [`proc_exec()`](fn.proc_exec.html). - ARGDATALEN = 257, - /// Base address at which the executable is placed in - /// memory. - BASE = 7, - /// Base address of a buffer of random data that may be - /// used for non-cryptographic purposes, for example as a - /// canary for stack smashing protection. - CANARY = 258, - /// Length of a buffer of random data that may be used - /// for non-cryptographic purposes, for example as a - /// canary for stack smashing protection. - CANARYLEN = 259, - /// Number of CPUs that the system this process is running - /// on has. - NCPUS = 260, - /// Terminator of the auxiliary vector. - NULL = 0, - /// Smallest memory object size for which individual - /// memory protection controls can be configured. - PAGESZ = 6, - /// Address of the first ELF program header of the - /// executable. - PHDR = 3, - /// Number of ELF program headers of the executable. - PHNUM = 4, - /// Identifier of the process. - /// - /// This environment does not provide any simple numerical - /// process identifiers, for the reason that these are not - /// useful in distributed contexts. Instead, processes are - /// identified by a UUID. - /// - /// This record should point to sixteen bytes of binary - /// data, containing a version 4 UUID (fully random). - PID = 263, - /// Address of the ELF header of the vDSO. - /// - /// The vDSO is a shared library that is mapped in the - /// address space of the process. It provides entry points - /// for every system call supported by the environment, - /// all having a corresponding symbol that is prefixed - /// with `cloudabi_sys_`. System calls should be invoked - /// through these entry points. - /// - /// The first advantage of letting processes call into a - /// vDSO to perform system calls instead of raising - /// hardware traps is that it allows for easy emulation of - /// executables on top of existing operating systems. The - /// second advantage is that in cases where an operating - /// system provides native support for CloudABI executables, - /// it may still implement partial userspace - /// implementations of these system calls to improve - /// performance (e.g., [`clock_time_get()`](fn.clock_time_get.html)). It also provides - /// a more dynamic way of adding, removing or replacing - /// system calls. - SYSINFO_EHDR = 262, - /// Thread ID of the initial thread of the process. - TID = 261, - #[doc(hidden)] _NonExhaustive = -1 as isize as u32, -} - -/// Identifiers for clocks. -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum clockid { - /// The system-wide monotonic clock, which is defined as a - /// clock measuring real time, whose value cannot be - /// adjusted and which cannot have negative clock jumps. - /// - /// The epoch of this clock is undefined. The absolute - /// time value of this clock therefore has no meaning. - MONOTONIC = 1, - /// The CPU-time clock associated with the current - /// process. - PROCESS_CPUTIME_ID = 2, - /// The system-wide clock measuring real time. Time value - /// zero corresponds with 1970-01-01T00:00:00Z. - REALTIME = 3, - /// The CPU-time clock associated with the current thread. - THREAD_CPUTIME_ID = 4, - #[doc(hidden)] _NonExhaustive = -1 as isize as u32, -} - -/// A userspace condition variable. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct condvar(pub u32); -/// The condition variable is in its initial state. There -/// are no threads waiting to be woken up. If the -/// condition variable has any other value, the kernel -/// must be called to wake up any sleeping threads. -pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0); - -/// Identifier for a device containing a file system. Can be used -/// in combination with [`inode`](struct.inode.html) to uniquely identify a file on the -/// local system. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct device(pub u64); - -/// A reference to the offset of a directory entry. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct dircookie(pub u64); -/// Permanent reference to the first directory entry -/// within a directory. -pub const DIRCOOKIE_START: dircookie = dircookie(0); - -/// Error codes returned by system calls. -/// -/// Not all of these error codes are returned by the system calls -/// provided by this environment, but are either used in userspace -/// exclusively or merely provided for alignment with POSIX. -#[repr(u16)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum errno { - /// No error occurred. System call completed successfully. - SUCCESS = 0, - /// Argument list too long. - TOOBIG = 1, - /// Permission denied. - ACCES = 2, - /// Address in use. - ADDRINUSE = 3, - /// Address not available. - ADDRNOTAVAIL = 4, - /// Address family not supported. - AFNOSUPPORT = 5, - /// Resource unavailable, or operation would block. - AGAIN = 6, - /// Connection already in progress. - ALREADY = 7, - /// Bad file descriptor. - BADF = 8, - /// Bad message. - BADMSG = 9, - /// Device or resource busy. - BUSY = 10, - /// Operation canceled. - CANCELED = 11, - /// No child processes. - CHILD = 12, - /// Connection aborted. - CONNABORTED = 13, - /// Connection refused. - CONNREFUSED = 14, - /// Connection reset. - CONNRESET = 15, - /// Resource deadlock would occur. - DEADLK = 16, - /// Destination address required. - DESTADDRREQ = 17, - /// Mathematics argument out of domain of function. - DOM = 18, - /// Reserved. - DQUOT = 19, - /// File exists. - EXIST = 20, - /// Bad address. - FAULT = 21, - /// File too large. - FBIG = 22, - /// Host is unreachable. - HOSTUNREACH = 23, - /// Identifier removed. - IDRM = 24, - /// Illegal byte sequence. - ILSEQ = 25, - /// Operation in progress. - INPROGRESS = 26, - /// Interrupted function. - INTR = 27, - /// Invalid argument. - INVAL = 28, - /// I/O error. - IO = 29, - /// Socket is connected. - ISCONN = 30, - /// Is a directory. - ISDIR = 31, - /// Too many levels of symbolic links. - LOOP = 32, - /// File descriptor value too large. - MFILE = 33, - /// Too many links. - MLINK = 34, - /// Message too large. - MSGSIZE = 35, - /// Reserved. - MULTIHOP = 36, - /// Filename too long. - NAMETOOLONG = 37, - /// Network is down. - NETDOWN = 38, - /// Connection aborted by network. - NETRESET = 39, - /// Network unreachable. - NETUNREACH = 40, - /// Too many files open in system. - NFILE = 41, - /// No buffer space available. - NOBUFS = 42, - /// No such device. - NODEV = 43, - /// No such file or directory. - NOENT = 44, - /// Executable file format error. - NOEXEC = 45, - /// No locks available. - NOLCK = 46, - /// Reserved. - NOLINK = 47, - /// Not enough space. - NOMEM = 48, - /// No message of the desired type. - NOMSG = 49, - /// Protocol not available. - NOPROTOOPT = 50, - /// No space left on device. - NOSPC = 51, - /// Function not supported. - NOSYS = 52, - /// The socket is not connected. - NOTCONN = 53, - /// Not a directory or a symbolic link to a directory. - NOTDIR = 54, - /// Directory not empty. - NOTEMPTY = 55, - /// State not recoverable. - NOTRECOVERABLE = 56, - /// Not a socket. - NOTSOCK = 57, - /// Not supported, or operation not supported on socket. - NOTSUP = 58, - /// Inappropriate I/O control operation. - NOTTY = 59, - /// No such device or address. - NXIO = 60, - /// Value too large to be stored in data type. - OVERFLOW = 61, - /// Previous owner died. - OWNERDEAD = 62, - /// Operation not permitted. - PERM = 63, - /// Broken pipe. - PIPE = 64, - /// Protocol error. - PROTO = 65, - /// Protocol not supported. - PROTONOSUPPORT = 66, - /// Protocol wrong type for socket. - PROTOTYPE = 67, - /// Result too large. - RANGE = 68, - /// Read-only file system. - ROFS = 69, - /// Invalid seek. - SPIPE = 70, - /// No such process. - SRCH = 71, - /// Reserved. - STALE = 72, - /// Connection timed out. - TIMEDOUT = 73, - /// Text file busy. - TXTBSY = 74, - /// Cross-device link. - XDEV = 75, - /// Extension: Capabilities insufficient. - NOTCAPABLE = 76, - #[doc(hidden)] _NonExhaustive = -1 as isize as u16, -} - -bitflags! { - /// The state of the file descriptor subscribed to with - /// [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - #[repr(C)] - pub struct eventrwflags: u16 { - /// The peer of this socket has closed or disconnected. - const HANGUP = 0x0001; - } -} - -/// Type of a subscription to an event or its occurrence. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum eventtype { - /// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id) - /// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout). - CLOCK = 1, - /// Condition variable [`subscription.union.condvar.condvar`](struct.subscription_condvar.html#structfield.condvar) has - /// been woken up and [`subscription.union.condvar.lock`](struct.subscription_condvar.html#structfield.lock) has been - /// acquired for writing. - CONDVAR = 2, - /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has - /// data available for reading. This event always triggers - /// for regular files. - FD_READ = 3, - /// File descriptor [`subscription.union.fd_readwrite.fd`](struct.subscription_fd_readwrite.html#structfield.fd) has - /// capacity available for writing. This event always - /// triggers for regular files. - FD_WRITE = 4, - /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for - /// reading. - LOCK_RDLOCK = 5, - /// Lock [`subscription.union.lock.lock`](struct.subscription_lock.html#structfield.lock) has been acquired for - /// writing. - LOCK_WRLOCK = 6, - /// The process associated with process descriptor - /// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated. - PROC_TERMINATE = 7, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, -} - -/// Exit code generated by a process when exiting. -pub type exitcode = u32; - -/// A file descriptor number. -/// -/// Unlike on POSIX-compliant systems, none of the file descriptor -/// numbers are reserved for a purpose (e.g., stdin, stdout, -/// stderr). Operating systems are not required to allocate new -/// file descriptors in ascending order. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct fd(pub u32); -/// Returned to the child process by [`proc_fork()`](fn.proc_fork.html). -pub const PROCESS_CHILD: fd = fd(0xffffffff); -/// Passed to [`mem_map()`](fn.mem_map.html) when creating a mapping to -/// anonymous memory. -pub const MAP_ANON_FD : fd = fd(0xffffffff); - -bitflags! { - /// File descriptor flags. - #[repr(C)] - pub struct fdflags: u16 { - /// Append mode: Data written to the file is always - /// appended to the file's end. - const APPEND = 0x0001; - /// Write according to synchronized I/O data integrity - /// completion. Only the data stored in the file is - /// synchronized. - const DSYNC = 0x0002; - /// Non-blocking mode. - const NONBLOCK = 0x0004; - /// Synchronized read I/O operations. - const RSYNC = 0x0008; - /// Write according to synchronized I/O file integrity - /// completion. In addition to synchronizing the data - /// stored in the file, the system may also synchronously - /// update the file's metadata. - const SYNC = 0x0010; - } -} - -bitflags! { - /// Which file descriptor attributes to adjust. - #[repr(C)] - pub struct fdsflags: u16 { - /// Adjust the file descriptor flags stored in - /// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags). - const FLAGS = 0x0001; - /// Restrict the rights of the file descriptor to the - /// rights stored in [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and - /// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting). - const RIGHTS = 0x0002; - } -} - -/// Relative offset within a file. -pub type filedelta = i64; - -/// Non-negative file size or length of a region within a file. -pub type filesize = u64; - -/// The type of a file descriptor or file. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum filetype { - /// The type of the file descriptor or file is unknown or - /// is different from any of the other types specified. - UNKNOWN = 0, - /// The file descriptor or file refers to a block device - /// inode. - BLOCK_DEVICE = 16, - /// The file descriptor or file refers to a character - /// device inode. - CHARACTER_DEVICE = 17, - /// The file descriptor or file refers to a directory - /// inode. - DIRECTORY = 32, - /// The file descriptor refers to a process handle. - PROCESS = 80, - /// The file descriptor or file refers to a regular file - /// inode. - REGULAR_FILE = 96, - /// The file descriptor refers to a shared memory object. - SHARED_MEMORY = 112, - /// The file descriptor or file refers to a datagram - /// socket. - SOCKET_DGRAM = 128, - /// The file descriptor or file refers to a byte-stream - /// socket. - SOCKET_STREAM = 130, - /// The file refers to a symbolic link inode. - SYMBOLIC_LINK = 144, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, -} - -bitflags! { - /// Which file attributes to adjust. - #[repr(C)] - pub struct fsflags: u16 { - /// Adjust the last data access timestamp to the value - /// stored in [`filestat.st_atim`](struct.filestat.html#structfield.st_atim). - const ATIM = 0x0001; - /// Adjust the last data access timestamp to the time - /// of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). - const ATIM_NOW = 0x0002; - /// Adjust the last data modification timestamp to the - /// value stored in [`filestat.st_mtim`](struct.filestat.html#structfield.st_mtim). - const MTIM = 0x0004; - /// Adjust the last data modification timestamp to the - /// time of clock [`REALTIME`](enum.clockid.html#variant.REALTIME). - const MTIM_NOW = 0x0008; - /// Truncate or extend the file to the size stored in - /// [`filestat.st_size`](struct.filestat.html#structfield.st_size). - const SIZE = 0x0010; - } -} - -/// File serial number that is unique within its file system. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct inode(pub u64); - -/// Number of hard links to an inode. -pub type linkcount = u32; - -/// A userspace read-recursive readers-writer lock, similar to a -/// Linux futex or a FreeBSD umtx. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct lock(pub u32); -/// Value indicating that the lock is in its initial -/// unlocked state. -pub const LOCK_UNLOCKED : lock = lock(0x00000000); -/// Bitmask indicating that the lock is write-locked. If -/// set, the lower 30 bits of the lock contain the -/// identifier of the thread that owns the write lock. -/// Otherwise, the lower 30 bits of the lock contain the -/// number of acquired read locks. -pub const LOCK_WRLOCKED : lock = lock(0x40000000); -/// Bitmask indicating that the lock is either read locked -/// or write locked, and that one or more threads have -/// their execution suspended, waiting to acquire the -/// lock. The last owner of the lock must call the -/// kernel to unlock. -/// -/// When the lock is acquired for reading and this bit is -/// set, it means that one or more threads are attempting -/// to acquire this lock for writing. In that case, other -/// threads should only acquire additional read locks if -/// suspending execution would cause a deadlock. It is -/// preferred to suspend execution, as this prevents -/// starvation of writers. -pub const LOCK_KERNEL_MANAGED: lock = lock(0x80000000); -/// Value indicating that the lock is in an incorrect -/// state. A lock cannot be in its initial unlocked state, -/// while also managed by the kernel. -pub const LOCK_BOGUS : lock = lock(0x80000000); - -bitflags! { - /// Flags determining the method of how paths are resolved. - #[repr(C)] - pub struct lookupflags: u32 { - /// As long as the resolved path corresponds to a symbolic - /// link, it is expanded. - const SYMLINK_FOLLOW = 0x00000001; - } -} - -bitflags! { - /// Memory mapping flags. - #[repr(C)] - pub struct mflags: u8 { - /// Instead of mapping the contents of the file provided, - /// create a mapping to anonymous memory. The file - /// descriptor argument must be set to [`MAP_ANON_FD`](constant.MAP_ANON_FD.html), - /// and the offset must be set to zero. - const ANON = 0x01; - /// Require that the mapping is performed at the base - /// address provided. - const FIXED = 0x02; - /// Changes are private. - const PRIVATE = 0x04; - /// Changes are shared. - const SHARED = 0x08; - } -} - -bitflags! { - /// Memory page protection options. - /// - /// This implementation enforces the `W^X` property: Pages cannot be - /// mapped for execution while also mapped for writing. - #[repr(C)] - pub struct mprot: u8 { - /// Page can be executed. - const EXEC = 0x01; - /// Page can be written. - const WRITE = 0x02; - /// Page can be read. - const READ = 0x04; - } -} - -bitflags! { - /// Methods of synchronizing memory with physical storage. - #[repr(C)] - pub struct msflags: u8 { - /// Perform asynchronous writes. - const ASYNC = 0x01; - /// Invalidate cached data. - const INVALIDATE = 0x02; - /// Perform synchronous writes. - const SYNC = 0x04; - } -} - -/// Specifies the number of threads sleeping on a condition -/// variable that should be woken up. -pub type nthreads = u32; - -bitflags! { - /// Open flags used by [`file_open()`](fn.file_open.html). - #[repr(C)] - pub struct oflags: u16 { - /// Create file if it does not exist. - const CREAT = 0x0001; - /// Fail if not a directory. - const DIRECTORY = 0x0002; - /// Fail if file already exists. - const EXCL = 0x0004; - /// Truncate file to size 0. - const TRUNC = 0x0008; - } -} - -bitflags! { - /// Flags provided to [`sock_recv()`](fn.sock_recv.html). - #[repr(C)] - pub struct riflags: u16 { - /// Returns the message without removing it from the - /// socket's receive queue. - const PEEK = 0x0004; - /// On byte-stream sockets, block until the full amount - /// of data can be returned. - const WAITALL = 0x0010; - } -} - -bitflags! { - /// File descriptor rights, determining which actions may be - /// performed. - #[repr(C)] - pub struct rights: u64 { - /// The right to invoke [`fd_datasync()`](fn.fd_datasync.html). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). - const FD_DATASYNC = 0x0000000000000001; - /// The right to invoke [`fd_read()`](fn.fd_read.html) and [`sock_recv()`](fn.sock_recv.html). - /// - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to - /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option - /// [`READ`](struct.mprot.html#associatedconstant.READ). - /// - /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to invoke - /// [`fd_pread()`](fn.fd_pread.html). - const FD_READ = 0x0000000000000002; - /// The right to invoke [`fd_seek()`](fn.fd_seek.html). This flag implies - /// [`FD_TELL`](struct.rights.html#associatedconstant.FD_TELL). - const FD_SEEK = 0x0000000000000004; - /// The right to invoke [`fd_stat_put()`](fn.fd_stat_put.html) with - /// [`FLAGS`](struct.fdsflags.html#associatedconstant.FLAGS). - const FD_STAT_PUT_FLAGS = 0x0000000000000008; - /// The right to invoke [`fd_sync()`](fn.fd_sync.html). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`RSYNC`](struct.fdflags.html#associatedconstant.RSYNC) and - /// [`DSYNC`](struct.fdflags.html#associatedconstant.DSYNC). - const FD_SYNC = 0x0000000000000010; - /// The right to invoke [`fd_seek()`](fn.fd_seek.html) in such a way that the - /// file offset remains unaltered (i.e., [`CUR`](enum.whence.html#variant.CUR) with - /// offset zero). - const FD_TELL = 0x0000000000000020; - /// The right to invoke [`fd_write()`](fn.fd_write.html) and [`sock_send()`](fn.sock_send.html). - /// - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, includes the right to - /// invoke [`mem_map()`](fn.mem_map.html) with memory protection option - /// [`WRITE`](struct.mprot.html#associatedconstant.WRITE). - /// - /// If [`FD_SEEK`](struct.rights.html#associatedconstant.FD_SEEK) is set, includes the right to - /// invoke [`fd_pwrite()`](fn.fd_pwrite.html). - const FD_WRITE = 0x0000000000000040; - /// The right to invoke [`file_advise()`](fn.file_advise.html). - const FILE_ADVISE = 0x0000000000000080; - /// The right to invoke [`file_allocate()`](fn.file_allocate.html). - const FILE_ALLOCATE = 0x0000000000000100; - /// The right to invoke [`file_create()`](fn.file_create.html) with - /// [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY). - const FILE_CREATE_DIRECTORY = 0x0000000000000200; - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, the right to invoke - /// [`file_open()`](fn.file_open.html) with [`CREAT`](struct.oflags.html#associatedconstant.CREAT). - const FILE_CREATE_FILE = 0x0000000000000400; - /// The right to invoke [`file_link()`](fn.file_link.html) with the file - /// descriptor as the source directory. - const FILE_LINK_SOURCE = 0x0000000000001000; - /// The right to invoke [`file_link()`](fn.file_link.html) with the file - /// descriptor as the target directory. - const FILE_LINK_TARGET = 0x0000000000002000; - /// The right to invoke [`file_open()`](fn.file_open.html). - const FILE_OPEN = 0x0000000000004000; - /// The right to invoke [`file_readdir()`](fn.file_readdir.html). - const FILE_READDIR = 0x0000000000008000; - /// The right to invoke [`file_readlink()`](fn.file_readlink.html). - const FILE_READLINK = 0x0000000000010000; - /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file - /// descriptor as the source directory. - const FILE_RENAME_SOURCE = 0x0000000000020000; - /// The right to invoke [`file_rename()`](fn.file_rename.html) with the file - /// descriptor as the target directory. - const FILE_RENAME_TARGET = 0x0000000000040000; - /// The right to invoke [`file_stat_fget()`](fn.file_stat_fget.html). - const FILE_STAT_FGET = 0x0000000000080000; - /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with - /// [`SIZE`](struct.fsflags.html#associatedconstant.SIZE). - /// - /// If [`FILE_OPEN`](struct.rights.html#associatedconstant.FILE_OPEN) is set, includes the right to - /// invoke [`file_open()`](fn.file_open.html) with [`TRUNC`](struct.oflags.html#associatedconstant.TRUNC). - const FILE_STAT_FPUT_SIZE = 0x0000000000100000; - /// The right to invoke [`file_stat_fput()`](fn.file_stat_fput.html) with - /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), - /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). - const FILE_STAT_FPUT_TIMES = 0x0000000000200000; - /// The right to invoke [`file_stat_get()`](fn.file_stat_get.html). - const FILE_STAT_GET = 0x0000000000400000; - /// The right to invoke [`file_stat_put()`](fn.file_stat_put.html) with - /// [`ATIM`](struct.fsflags.html#associatedconstant.ATIM), [`ATIM_NOW`](struct.fsflags.html#associatedconstant.ATIM_NOW), [`MTIM`](struct.fsflags.html#associatedconstant.MTIM), - /// and [`MTIM_NOW`](struct.fsflags.html#associatedconstant.MTIM_NOW). - const FILE_STAT_PUT_TIMES = 0x0000000000800000; - /// The right to invoke [`file_symlink()`](fn.file_symlink.html). - const FILE_SYMLINK = 0x0000000001000000; - /// The right to invoke [`file_unlink()`](fn.file_unlink.html). - const FILE_UNLINK = 0x0000000002000000; - /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`](struct.mprot.html) set to - /// zero. - const MEM_MAP = 0x0000000004000000; - /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke - /// [`mem_map()`](fn.mem_map.html) with [`EXEC`](struct.mprot.html#associatedconstant.EXEC). - const MEM_MAP_EXEC = 0x0000000008000000; - /// If [`FD_READ`](struct.rights.html#associatedconstant.FD_READ) is set, includes the right to - /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_READ`](enum.eventtype.html#variant.FD_READ). - /// - /// If [`FD_WRITE`](struct.rights.html#associatedconstant.FD_WRITE) is set, includes the right to - /// invoke [`poll()`](fn.poll.html) to subscribe to [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - const POLL_FD_READWRITE = 0x0000000010000000; - /// The right to invoke [`poll()`](fn.poll.html) to subscribe to - /// [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - const POLL_PROC_TERMINATE = 0x0000000040000000; - /// The right to invoke [`proc_exec()`](fn.proc_exec.html). - const PROC_EXEC = 0x0000000100000000; - /// The right to invoke [`sock_shutdown()`](fn.sock_shutdown.html). - const SOCK_SHUTDOWN = 0x0000008000000000; - } -} - -bitflags! { - /// Flags returned by [`sock_recv()`](fn.sock_recv.html). - #[repr(C)] - pub struct roflags: u16 { - /// Returned by [`sock_recv()`](fn.sock_recv.html): List of file descriptors - /// has been truncated. - const FDS_TRUNCATED = 0x0001; - /// Returned by [`sock_recv()`](fn.sock_recv.html): Message data has been - /// truncated. - const DATA_TRUNCATED = 0x0008; - } -} - -/// Indicates whether an object is stored in private or shared -/// memory. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum scope { - /// The object is stored in private memory. - PRIVATE = 4, - /// The object is stored in shared memory. - SHARED = 8, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, -} - -bitflags! { - /// Which channels on a socket need to be shut down. - #[repr(C)] - pub struct sdflags: u8 { - /// Disables further receive operations. - const RD = 0x01; - /// Disables further send operations. - const WR = 0x02; - } -} - -bitflags! { - /// Flags provided to [`sock_send()`](fn.sock_send.html). As there are currently no flags - /// defined, it must be set to zero. - #[repr(C)] - pub struct siflags: u16 { - const DEFAULT = 0; - } -} - -/// Signal condition. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum signal { - /// Process abort signal. - /// - /// Action: Terminates the process. - ABRT = 1, - /// Alarm clock. - /// - /// Action: Terminates the process. - ALRM = 2, - /// Access to an undefined portion of a memory object. - /// - /// Action: Terminates the process. - BUS = 3, - /// Child process terminated, stopped, or continued. - /// - /// Action: Ignored. - CHLD = 4, - /// Continue executing, if stopped. - /// - /// Action: Continues executing, if stopped. - CONT = 5, - /// Erroneous arithmetic operation. - /// - /// Action: Terminates the process. - FPE = 6, - /// Hangup. - /// - /// Action: Terminates the process. - HUP = 7, - /// Illegal instruction. - /// - /// Action: Terminates the process. - ILL = 8, - /// Terminate interrupt signal. - /// - /// Action: Terminates the process. - INT = 9, - /// Kill. - /// - /// Action: Terminates the process. - KILL = 10, - /// Write on a pipe with no one to read it. - /// - /// Action: Ignored. - PIPE = 11, - /// Terminal quit signal. - /// - /// Action: Terminates the process. - QUIT = 12, - /// Invalid memory reference. - /// - /// Action: Terminates the process. - SEGV = 13, - /// Stop executing. - /// - /// Action: Stops executing. - STOP = 14, - /// Bad system call. - /// - /// Action: Terminates the process. - SYS = 15, - /// Termination signal. - /// - /// Action: Terminates the process. - TERM = 16, - /// Trace/breakpoint trap. - /// - /// Action: Terminates the process. - TRAP = 17, - /// Terminal stop signal. - /// - /// Action: Stops executing. - TSTP = 18, - /// Background process attempting read. - /// - /// Action: Stops executing. - TTIN = 19, - /// Background process attempting write. - /// - /// Action: Stops executing. - TTOU = 20, - /// High bandwidth data is available at a socket. - /// - /// Action: Ignored. - URG = 21, - /// User-defined signal 1. - /// - /// Action: Terminates the process. - USR1 = 22, - /// User-defined signal 2. - /// - /// Action: Terminates the process. - USR2 = 23, - /// Virtual timer expired. - /// - /// Action: Terminates the process. - VTALRM = 24, - /// CPU time limit exceeded. - /// - /// Action: Terminates the process. - XCPU = 25, - /// File size limit exceeded. - /// - /// Action: Terminates the process. - XFSZ = 26, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, -} - -bitflags! { - /// Flags determining how the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) should be interpreted. - #[repr(C)] - pub struct subclockflags: u16 { - /// If set, treat the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) as an absolute timestamp - /// of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). - /// - /// If clear, treat the timestamp provided in - /// [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout) relative to the current - /// time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id). - const ABSTIME = 0x0001; - } -} - -bitflags! { - /// Flags influencing the method of polling for read or writing on - /// a file descriptor. - #[repr(C)] - pub struct subrwflags: u16 { - /// Deprecated. Must be set by callers and ignored by - /// implementations. - const POLL = 0x0001; - } -} - -/// Unique system-local identifier of a thread. This identifier is -/// only valid during the lifetime of the thread. -/// -/// Threads must be aware of their thread identifier, as it is -/// written it into locks when acquiring them for writing. It is -/// not advised to use these identifiers for any other purpose. -/// -/// As the thread identifier is also stored in [`lock`](struct.lock.html) when -/// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread -/// must always be set to zero. -#[repr(C)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct tid(pub u32); - -/// Timestamp in nanoseconds. -pub type timestamp = u64; - -bitflags! { - /// Specifies whether files are unlinked or directories are - /// removed. - #[repr(C)] - pub struct ulflags: u8 { - /// If set, removes a directory. Otherwise, unlinks any - /// non-directory file. - const REMOVEDIR = 0x01; - } -} - -/// User-provided value that can be attached to objects that is -/// retained when extracted from the kernel. -pub type userdata = u64; - -/// Relative to which position the offset of the file descriptor -/// should be set. -#[repr(u8)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum whence { - /// Seek relative to current position. - CUR = 1, - /// Seek relative to end-of-file. - END = 2, - /// Seek relative to start-of-file. - SET = 3, - #[doc(hidden)] _NonExhaustive = -1 as isize as u8, -} - -/// Auxiliary vector entry. -/// -/// The auxiliary vector is a list of key-value pairs that is -/// provided to the process on startup. Unlike structures, it is -/// extensible, as it is possible to add new records later on. -/// The auxiliary vector is always terminated by an entry having -/// type [`NULL`](enum.auxtype.html#variant.NULL). -/// -/// The auxiliary vector is part of the x86-64 ABI, but is used by -/// this environment on all architectures. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct auxv { - /// The type of the auxiliary vector entry. - pub a_type: auxtype, - pub union: auxv_union -} -/// A union inside `auxv`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union auxv_union { - /// Used when `a_type` is [`ARGDATALEN`](enum.auxtype.html#variant.ARGDATALEN), [`CANARYLEN`](enum.auxtype.html#variant.CANARYLEN), [`NCPUS`](enum.auxtype.html#variant.NCPUS), [`PAGESZ`](enum.auxtype.html#variant.PAGESZ), [`PHNUM`](enum.auxtype.html#variant.PHNUM), or [`TID`](enum.auxtype.html#variant.TID). -/// A numerical value. - pub a_val: usize, - /// Used when `a_type` is [`ARGDATA`](enum.auxtype.html#variant.ARGDATA), [`BASE`](enum.auxtype.html#variant.BASE), [`CANARY`](enum.auxtype.html#variant.CANARY), [`PHDR`](enum.auxtype.html#variant.PHDR), [`PID`](enum.auxtype.html#variant.PID), or [`SYSINFO_EHDR`](enum.auxtype.html#variant.SYSINFO_EHDR). -/// A pointer value. - pub a_ptr: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn auxv_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: auxv = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.a_type as *const _ as usize - base, 0); - assert_eq!(&obj.union.a_val as *const _ as usize - base, 4); - assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn auxv_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: auxv = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.a_type as *const _ as usize - base, 0); - assert_eq!(&obj.union.a_val as *const _ as usize - base, 8); - assert_eq!(&obj.union.a_ptr as *const _ as usize - base, 8); - } -} - -/// A region of memory for scatter/gather writes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ciovec { - /// The address and length of the buffer to be written. - pub buf: (*const (), usize), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn ciovec_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: ciovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn ciovec_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: ciovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); - } -} - -/// A directory entry. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct dirent { - /// The offset of the next directory entry stored in this - /// directory. - pub d_next: dircookie, - /// The serial number of the file referred to by this - /// directory entry. - pub d_ino: inode, - /// The length of the name of the directory entry. - pub d_namlen: u32, - /// The type of the file referred to by this directory - /// entry. - pub d_type: filetype, -} -#[test] -fn dirent_layout_test() { - assert_eq!(::core::mem::size_of::(), 24); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: dirent = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.d_next as *const _ as usize - base, 0); - assert_eq!(&obj.d_ino as *const _ as usize - base, 8); - assert_eq!(&obj.d_namlen as *const _ as usize - base, 16); - assert_eq!(&obj.d_type as *const _ as usize - base, 20); - } -} - -/// An event that occurred. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event { - /// User-provided value that got attached to - /// [`subscription.userdata`](struct.subscription.html#structfield.userdata). - pub userdata: userdata, - /// If non-zero, an error that occurred while processing - /// the subscription request. - pub error: errno, - /// The type of the event that occurred. - pub type_: eventtype, - pub union: event_union -} -/// A union inside `event`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union event_union { - /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - pub fd_readwrite: event_fd_readwrite, - /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - pub proc_terminate: event_proc_terminate, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event_fd_readwrite { - /// The number of bytes available - /// for reading or writing. - pub nbytes: filesize, - /// Obsolete. - pub unused: [u8; 4], - /// The state of the file - /// descriptor. - pub flags: eventrwflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct event_proc_terminate { - /// Obsolete. - pub unused: [u8; 4], - /// If zero, the process has - /// exited. - /// Otherwise, the signal - /// condition causing it to - /// terminated. - pub signal: signal, - /// If exited, the exit code of - /// the process. - pub exitcode: exitcode, -} -#[test] -fn event_layout_test() { - assert_eq!(::core::mem::size_of::(), 32); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: event = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.error as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.fd_readwrite.nbytes as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.unused as *const _ as usize - base, 24); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 28); - assert_eq!(&obj.union.proc_terminate.unused as *const _ as usize - base, 16); - assert_eq!(&obj.union.proc_terminate.signal as *const _ as usize - base, 20); - assert_eq!(&obj.union.proc_terminate.exitcode as *const _ as usize - base, 24); - } -} - -/// File descriptor attributes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct fdstat { - /// File type. - pub fs_filetype: filetype, - /// File descriptor flags. - pub fs_flags: fdflags, - /// Rights that apply to this file descriptor. - pub fs_rights_base: rights, - /// Maximum set of rights that can be installed on new - /// file descriptors that are created through this file - /// descriptor, e.g., through [`file_open()`](fn.file_open.html). - pub fs_rights_inheriting: rights, -} -#[test] -fn fdstat_layout_test() { - assert_eq!(::core::mem::size_of::(), 24); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: fdstat = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.fs_filetype as *const _ as usize - base, 0); - assert_eq!(&obj.fs_flags as *const _ as usize - base, 2); - assert_eq!(&obj.fs_rights_base as *const _ as usize - base, 8); - assert_eq!(&obj.fs_rights_inheriting as *const _ as usize - base, 16); - } -} - -/// File attributes. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct filestat { - /// Device ID of device containing the file. - pub st_dev: device, - /// File serial number. - pub st_ino: inode, - /// File type. - pub st_filetype: filetype, - /// Number of hard links to the file. - pub st_nlink: linkcount, - /// For regular files, the file size in bytes. For - /// symbolic links, the length in bytes of the pathname - /// contained in the symbolic link. - pub st_size: filesize, - /// Last data access timestamp. - pub st_atim: timestamp, - /// Last data modification timestamp. - pub st_mtim: timestamp, - /// Last file status change timestamp. - pub st_ctim: timestamp, -} -#[test] -fn filestat_layout_test() { - assert_eq!(::core::mem::size_of::(), 56); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: filestat = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.st_dev as *const _ as usize - base, 0); - assert_eq!(&obj.st_ino as *const _ as usize - base, 8); - assert_eq!(&obj.st_filetype as *const _ as usize - base, 16); - assert_eq!(&obj.st_nlink as *const _ as usize - base, 20); - assert_eq!(&obj.st_size as *const _ as usize - base, 24); - assert_eq!(&obj.st_atim as *const _ as usize - base, 32); - assert_eq!(&obj.st_mtim as *const _ as usize - base, 40); - assert_eq!(&obj.st_ctim as *const _ as usize - base, 48); - } -} - -/// A region of memory for scatter/gather reads. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct iovec { - /// The address and length of the buffer to be filled. - pub buf: (*mut (), usize), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn iovec_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: iovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 4); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn iovec_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: iovec = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.buf.0 as *const _ as usize - base, 0); - assert_eq!(&obj.buf.1 as *const _ as usize - base, 8); - } -} - -/// Path lookup properties. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct lookup { - /// The working directory at which the resolution of the - /// path starts. - pub fd: fd, - /// Flags determining the method of how the path is - /// resolved. - pub flags: lookupflags, -} -#[test] -fn lookup_layout_test() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: lookup = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.fd as *const _ as usize - base, 0); - assert_eq!(&obj.flags as *const _ as usize - base, 4); - } -} - -/// Entry point for a process (`_start`). -/// -/// **auxv**: -/// The auxiliary vector. See [`auxv`](struct.auxv.html). -pub type processentry = unsafe extern "C" fn( - auxv: *const auxv, -) -> (); - -/// Arguments of [`sock_recv()`](fn.sock_recv.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct recv_in { - /// List of scatter/gather vectors where message data - /// should be stored. - pub ri_data: (*const iovec, usize), - /// Buffer where numbers of incoming file descriptors - /// should be stored. - pub ri_fds: (*mut fd, usize), - /// Message flags. - pub ri_flags: riflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn recv_in_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 20); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: recv_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 4); - assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 8); - assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 12); - assert_eq!(&obj.ri_flags as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn recv_in_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 40); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: recv_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ri_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.ri_data.1 as *const _ as usize - base, 8); - assert_eq!(&obj.ri_fds.0 as *const _ as usize - base, 16); - assert_eq!(&obj.ri_fds.1 as *const _ as usize - base, 24); - assert_eq!(&obj.ri_flags as *const _ as usize - base, 32); - } -} - -/// Results of [`sock_recv()`](fn.sock_recv.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct recv_out { - /// Number of bytes stored in [`recv_in.ri_data`](struct.recv_in.html#structfield.ri_data). - pub ro_datalen: usize, - /// Number of file descriptors stored in [`recv_in.ri_fds`](struct.recv_in.html#structfield.ri_fds). - pub ro_fdslen: usize, - /// Fields that were used by previous implementations. - pub ro_unused: [u8; 40], - /// Message flags. - pub ro_flags: roflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn recv_out_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 52); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: recv_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); - assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 4); - assert_eq!(&obj.ro_unused as *const _ as usize - base, 8); - assert_eq!(&obj.ro_flags as *const _ as usize - base, 48); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn recv_out_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 64); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: recv_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.ro_datalen as *const _ as usize - base, 0); - assert_eq!(&obj.ro_fdslen as *const _ as usize - base, 8); - assert_eq!(&obj.ro_unused as *const _ as usize - base, 16); - assert_eq!(&obj.ro_flags as *const _ as usize - base, 56); - } -} - -/// Arguments of [`sock_send()`](fn.sock_send.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct send_in { - /// List of scatter/gather vectors where message data - /// should be retrieved. - pub si_data: (*const ciovec, usize), - /// File descriptors that need to be attached to the - /// message. - pub si_fds: (*const fd, usize), - /// Message flags. - pub si_flags: siflags, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn send_in_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 20); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: send_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.si_data.1 as *const _ as usize - base, 4); - assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 8); - assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 12); - assert_eq!(&obj.si_flags as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn send_in_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 40); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: send_in = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.si_data.0 as *const _ as usize - base, 0); - assert_eq!(&obj.si_data.1 as *const _ as usize - base, 8); - assert_eq!(&obj.si_fds.0 as *const _ as usize - base, 16); - assert_eq!(&obj.si_fds.1 as *const _ as usize - base, 24); - assert_eq!(&obj.si_flags as *const _ as usize - base, 32); - } -} - -/// Results of [`sock_send()`](fn.sock_send.html). -#[repr(C)] -#[derive(Copy, Clone)] -pub struct send_out { - /// Number of bytes transmitted. - pub so_datalen: usize, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn send_out_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 4); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: send_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn send_out_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: send_out = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.so_datalen as *const _ as usize - base, 0); - } -} - -/// Subscription to an event. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription { - /// User-provided value that is attached to the - /// subscription in the kernel and returned through - /// [`event.userdata`](struct.event.html#structfield.userdata). - pub userdata: userdata, - /// Used by previous implementations. Ignored. - pub unused: u16, - /// The type of the event to which to subscribe. - /// - /// Currently, [`CONDVAR`](enum.eventtype.html#variant.CONDVAR), - /// [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK), and [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK) - /// must be provided as the first subscription and may - /// only be followed by up to one other subscription, - /// having type [`CLOCK`](enum.eventtype.html#variant.CLOCK). - pub type_: eventtype, - pub union: subscription_union -} -/// A union inside `subscription`. -#[repr(C)] -#[derive(Copy, Clone)] -pub union subscription_union { - /// Used when `type_` is [`CLOCK`](enum.eventtype.html#variant.CLOCK). - pub clock: subscription_clock, - /// Used when `type_` is [`CONDVAR`](enum.eventtype.html#variant.CONDVAR). - pub condvar: subscription_condvar, - /// Used when `type_` is [`FD_READ`](enum.eventtype.html#variant.FD_READ) or [`FD_WRITE`](enum.eventtype.html#variant.FD_WRITE). - pub fd_readwrite: subscription_fd_readwrite, - /// Used when `type_` is [`LOCK_RDLOCK`](enum.eventtype.html#variant.LOCK_RDLOCK) or [`LOCK_WRLOCK`](enum.eventtype.html#variant.LOCK_WRLOCK). - pub lock: subscription_lock, - /// Used when `type_` is [`PROC_TERMINATE`](enum.eventtype.html#variant.PROC_TERMINATE). - pub proc_terminate: subscription_proc_terminate, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_clock { - /// The user-defined unique - /// identifier of the clock. - pub identifier: userdata, - /// The clock against which the - /// timestamp should be compared. - pub clock_id: clockid, - /// The absolute or relative - /// timestamp. - pub timeout: timestamp, - /// The amount of time that the - /// kernel may wait additionally - /// to coalesce with other events. - pub precision: timestamp, - /// Flags specifying whether the - /// timeout is absolute or - /// relative. - pub flags: subclockflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_condvar { - /// The condition variable on - /// which to wait to be woken up. - pub condvar: *mut condvar, - /// The lock that will be - /// released while waiting. - /// - /// The lock will be reacquired - /// for writing when the condition - /// variable triggers. - pub lock: *mut lock, - /// Whether the condition variable - /// is stored in private or shared - /// memory. - pub condvar_scope: scope, - /// Whether the lock is stored in - /// private or shared memory. - pub lock_scope: scope, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_fd_readwrite { - /// The file descriptor on which - /// to wait for it to become ready - /// for reading or writing. - pub fd: fd, - /// Under which conditions to - /// trigger. - pub flags: subrwflags, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_lock { - /// The lock that will be acquired - /// for reading or writing. - pub lock: *mut lock, - /// Whether the lock is stored in - /// private or shared memory. - pub lock_scope: scope, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct subscription_proc_terminate { - /// The process descriptor on - /// which to wait for process - /// termination. - pub fd: fd, -} -#[test] -#[cfg(target_pointer_width = "32")] -fn subscription_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 56); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: subscription = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.unused as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); - assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); - assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); - assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); - assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); - assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); - assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 20); - assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 24); - assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 25); - assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); - assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); - assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 20); - assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn subscription_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 56); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: subscription = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.userdata as *const _ as usize - base, 0); - assert_eq!(&obj.unused as *const _ as usize - base, 8); - assert_eq!(&obj.type_ as *const _ as usize - base, 10); - assert_eq!(&obj.union.clock.identifier as *const _ as usize - base, 16); - assert_eq!(&obj.union.clock.clock_id as *const _ as usize - base, 24); - assert_eq!(&obj.union.clock.timeout as *const _ as usize - base, 32); - assert_eq!(&obj.union.clock.precision as *const _ as usize - base, 40); - assert_eq!(&obj.union.clock.flags as *const _ as usize - base, 48); - assert_eq!(&obj.union.condvar.condvar as *const _ as usize - base, 16); - assert_eq!(&obj.union.condvar.lock as *const _ as usize - base, 24); - assert_eq!(&obj.union.condvar.condvar_scope as *const _ as usize - base, 32); - assert_eq!(&obj.union.condvar.lock_scope as *const _ as usize - base, 33); - assert_eq!(&obj.union.fd_readwrite.fd as *const _ as usize - base, 16); - assert_eq!(&obj.union.fd_readwrite.flags as *const _ as usize - base, 20); - assert_eq!(&obj.union.lock.lock as *const _ as usize - base, 16); - assert_eq!(&obj.union.lock.lock_scope as *const _ as usize - base, 24); - assert_eq!(&obj.union.proc_terminate.fd as *const _ as usize - base, 16); - } -} - -/// The Thread Control Block (TCB). -/// -/// After a thread begins execution (at program startup or when -/// created through [`thread_create()`](fn.thread_create.html)), the CPU's registers -/// controlling Thread-Local Storage (TLS) will already be -/// initialized. They will point to an area only containing the -/// TCB. -/// -/// If the thread needs space for storing thread-specific -/// variables, the thread may allocate a larger area and adjust -/// the CPU's registers to point to that area instead. However, it -/// does need to make sure that the TCB is copied over to the new -/// TLS area. -/// -/// The purpose of the TCB is that it allows light-weight -/// emulators to store information related to individual threads. -/// For example, it may be used to store a copy of the CPU -/// registers prior emulation, so that TLS for the host system -/// can be restored if needed. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct tcb { - /// Pointer that may be freely assigned by the system. Its - /// value cannot be interpreted by the application. - pub parent: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn tcb_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 4); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: tcb = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.parent as *const _ as usize - base, 0); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn tcb_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 8); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: tcb = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.parent as *const _ as usize - base, 0); - } -} - -/// Entry point for additionally created threads. -/// -/// **tid**: -/// Thread ID of the current thread. -/// -/// **aux**: -/// Copy of the value stored in -/// [`threadattr.argument`](struct.threadattr.html#structfield.argument). -pub type threadentry = unsafe extern "C" fn( - tid: tid, - aux: *mut (), -) -> (); - -/// Attributes for thread creation. -#[repr(C)] -#[derive(Copy, Clone)] -pub struct threadattr { - /// Initial program counter value. - pub entry_point: threadentry, - /// Region allocated to serve as stack space. - pub stack: (*mut (), usize), - /// Argument to be forwarded to the entry point function. - pub argument: *mut (), -} -#[test] -#[cfg(target_pointer_width = "32")] -fn threadattr_layout_test_32() { - assert_eq!(::core::mem::size_of::(), 16); - assert_eq!(::core::mem::align_of::(), 4); - unsafe { - let obj: threadattr = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.entry_point as *const _ as usize - base, 0); - assert_eq!(&obj.stack.0 as *const _ as usize - base, 4); - assert_eq!(&obj.stack.1 as *const _ as usize - base, 8); - assert_eq!(&obj.argument as *const _ as usize - base, 12); - } -} -#[test] -#[cfg(target_pointer_width = "64")] -fn threadattr_layout_test_64() { - assert_eq!(::core::mem::size_of::(), 32); - assert_eq!(::core::mem::align_of::(), 8); - unsafe { - let obj: threadattr = ::core::mem::uninitialized(); - let base = &obj as *const _ as usize; - assert_eq!(&obj.entry_point as *const _ as usize - base, 0); - assert_eq!(&obj.stack.0 as *const _ as usize - base, 8); - assert_eq!(&obj.stack.1 as *const _ as usize - base, 16); - assert_eq!(&obj.argument as *const _ as usize - base, 24); - } -} - -/// The table with pointers to all syscall implementations. -#[allow(improper_ctypes)] -extern "C" { - fn cloudabi_sys_clock_res_get(_: clockid, _: *mut timestamp) -> errno; - fn cloudabi_sys_clock_time_get(_: clockid, _: timestamp, _: *mut timestamp) -> errno; - fn cloudabi_sys_condvar_signal(_: *mut condvar, _: scope, _: nthreads) -> errno; - fn cloudabi_sys_fd_close(_: fd) -> errno; - fn cloudabi_sys_fd_create1(_: filetype, _: *mut fd) -> errno; - fn cloudabi_sys_fd_create2(_: filetype, _: *mut fd, _: *mut fd) -> errno; - fn cloudabi_sys_fd_datasync(_: fd) -> errno; - fn cloudabi_sys_fd_dup(_: fd, _: *mut fd) -> errno; - fn cloudabi_sys_fd_pread(_: fd, _: *const iovec, _: usize, _: filesize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_pwrite(_: fd, _: *const ciovec, _: usize, _: filesize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_read(_: fd, _: *const iovec, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_fd_replace(_: fd, _: fd) -> errno; - fn cloudabi_sys_fd_seek(_: fd, _: filedelta, _: whence, _: *mut filesize) -> errno; - fn cloudabi_sys_fd_stat_get(_: fd, _: *mut fdstat) -> errno; - fn cloudabi_sys_fd_stat_put(_: fd, _: *const fdstat, _: fdsflags) -> errno; - fn cloudabi_sys_fd_sync(_: fd) -> errno; - fn cloudabi_sys_fd_write(_: fd, _: *const ciovec, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_file_advise(_: fd, _: filesize, _: filesize, _: advice) -> errno; - fn cloudabi_sys_file_allocate(_: fd, _: filesize, _: filesize) -> errno; - fn cloudabi_sys_file_create(_: fd, _: *const u8, _: usize, _: filetype) -> errno; - fn cloudabi_sys_file_link(_: lookup, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_open(_: lookup, _: *const u8, _: usize, _: oflags, _: *const fdstat, _: *mut fd) -> errno; - fn cloudabi_sys_file_readdir(_: fd, _: *mut (), _: usize, _: dircookie, _: *mut usize) -> errno; - fn cloudabi_sys_file_readlink(_: fd, _: *const u8, _: usize, _: *mut u8, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_file_rename(_: fd, _: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_stat_fget(_: fd, _: *mut filestat) -> errno; - fn cloudabi_sys_file_stat_fput(_: fd, _: *const filestat, _: fsflags) -> errno; - fn cloudabi_sys_file_stat_get(_: lookup, _: *const u8, _: usize, _: *mut filestat) -> errno; - fn cloudabi_sys_file_stat_put(_: lookup, _: *const u8, _: usize, _: *const filestat, _: fsflags) -> errno; - fn cloudabi_sys_file_symlink(_: *const u8, _: usize, _: fd, _: *const u8, _: usize) -> errno; - fn cloudabi_sys_file_unlink(_: fd, _: *const u8, _: usize, _: ulflags) -> errno; - fn cloudabi_sys_lock_unlock(_: *mut lock, _: scope) -> errno; - fn cloudabi_sys_mem_advise(_: *mut (), _: usize, _: advice) -> errno; - fn cloudabi_sys_mem_map(_: *mut (), _: usize, _: mprot, _: mflags, _: fd, _: filesize, _: *mut *mut ()) -> errno; - fn cloudabi_sys_mem_protect(_: *mut (), _: usize, _: mprot) -> errno; - fn cloudabi_sys_mem_sync(_: *mut (), _: usize, _: msflags) -> errno; - fn cloudabi_sys_mem_unmap(_: *mut (), _: usize) -> errno; - fn cloudabi_sys_poll(_: *const subscription, _: *mut event, _: usize, _: *mut usize) -> errno; - fn cloudabi_sys_proc_exec(_: fd, _: *const (), _: usize, _: *const fd, _: usize) -> errno; - fn cloudabi_sys_proc_exit(_: exitcode) -> !; - fn cloudabi_sys_proc_fork(_: *mut fd, _: *mut tid) -> errno; - fn cloudabi_sys_proc_raise(_: signal) -> errno; - fn cloudabi_sys_random_get(_: *mut (), _: usize) -> errno; - fn cloudabi_sys_sock_recv(_: fd, _: *const recv_in, _: *mut recv_out) -> errno; - fn cloudabi_sys_sock_send(_: fd, _: *const send_in, _: *mut send_out) -> errno; - fn cloudabi_sys_sock_shutdown(_: fd, _: sdflags) -> errno; - fn cloudabi_sys_thread_create(_: *mut threadattr, _: *mut tid) -> errno; - fn cloudabi_sys_thread_exit(_: *mut lock, _: scope) -> !; - fn cloudabi_sys_thread_yield() -> errno; -} - -/// Obtains the resolution of a clock. -/// -/// ## Parameters -/// -/// **clock_id**: -/// The clock for which the resolution needs to be -/// returned. -/// -/// **resolution**: -/// The resolution of the clock. -#[inline] -pub unsafe fn clock_res_get(clock_id_: clockid, resolution_: &mut timestamp) -> errno { - cloudabi_sys_clock_res_get(clock_id_, resolution_) -} - -/// Obtains the time value of a clock. -/// -/// ## Parameters -/// -/// **clock_id**: -/// The clock for which the time needs to be -/// returned. -/// -/// **precision**: -/// The maximum lag (exclusive) that the returned -/// time value may have, compared to its actual -/// value. -/// -/// **time**: -/// The time value of the clock. -#[inline] -pub unsafe fn clock_time_get(clock_id_: clockid, precision_: timestamp, time_: &mut timestamp) -> errno { - cloudabi_sys_clock_time_get(clock_id_, precision_, time_) -} - -/// Wakes up threads waiting on a userspace condition variable. -/// -/// If an invocation of this system call causes all waiting -/// threads to be woken up, the value of the condition variable -/// is set to [`CONDVAR_HAS_NO_WAITERS`](constant.CONDVAR_HAS_NO_WAITERS.html). As long as the condition -/// variable is set to this value, it is not needed to invoke this -/// system call. -/// -/// ## Parameters -/// -/// **condvar**: -/// The userspace condition variable that has -/// waiting threads. -/// -/// **scope**: -/// Whether the condition variable is stored in -/// private or shared memory. -/// -/// **nwaiters**: -/// The number of threads that need to be woken -/// up. If it exceeds the number of waiting -/// threads, all threads are woken up. -#[inline] -pub unsafe fn condvar_signal(condvar_: *mut condvar, scope_: scope, nwaiters_: nthreads) -> errno { - cloudabi_sys_condvar_signal(condvar_, scope_, nwaiters_) -} - -/// Closes a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor that needs to be closed. -#[inline] -pub unsafe fn fd_close(fd_: fd) -> errno { - cloudabi_sys_fd_close(fd_) -} - -/// Creates a file descriptor. -/// -/// ## Parameters -/// -/// **type**: -/// Possible values: -/// -/// - [`SHARED_MEMORY`](enum.filetype.html#variant.SHARED_MEMORY): -/// Creates an anonymous shared memory -/// object. -/// -/// **fd**: -/// The file descriptor that has been created. -#[inline] -pub unsafe fn fd_create1(type_: filetype, fd_: &mut fd) -> errno { - cloudabi_sys_fd_create1(type_, fd_) -} - -/// Creates a pair of file descriptors. -/// -/// ## Parameters -/// -/// **type**: -/// Possible values: -/// -/// - [`SOCKET_DGRAM`](enum.filetype.html#variant.SOCKET_DGRAM): -/// Creates a UNIX datagram socket pair. -/// - [`SOCKET_STREAM`](enum.filetype.html#variant.SOCKET_STREAM): -/// Creates a UNIX byte-stream socket -/// pair. -/// -/// **fd1**: -/// The first file descriptor of the pair. -/// -/// **fd2**: -/// The second file descriptor of the pair. -#[inline] -pub unsafe fn fd_create2(type_: filetype, fd1_: &mut fd, fd2_: &mut fd) -> errno { - cloudabi_sys_fd_create2(type_, fd1_, fd2_) -} - -/// Synchronizes the data of a file to disk. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor of the file whose data -/// needs to be synchronized to disk. -#[inline] -pub unsafe fn fd_datasync(fd_: fd) -> errno { - cloudabi_sys_fd_datasync(fd_) -} - -/// Duplicates a file descriptor. -/// -/// ## Parameters -/// -/// **from**: -/// The file descriptor that needs to be -/// duplicated. -/// -/// **fd**: -/// The new file descriptor. -#[inline] -pub unsafe fn fd_dup(from_: fd, fd_: &mut fd) -> errno { - cloudabi_sys_fd_dup(from_, fd_) -} - -/// Reads from a file descriptor, without using and updating the -/// file descriptor's offset. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor from which data should be -/// read. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be stored. -/// -/// **offset**: -/// The offset within the file at which reading -/// should start. -/// -/// **nread**: -/// The number of bytes read. -#[inline] -pub unsafe fn fd_pread(fd_: fd, iovs_: &[iovec], offset_: filesize, nread_: &mut usize) -> errno { - cloudabi_sys_fd_pread(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nread_) -} - -/// Writes to a file descriptor, without using and updating the -/// file descriptor's offset. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor to which data should be -/// written. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be retrieved. -/// -/// **offset**: -/// The offset within the file at which writing -/// should start. -/// -/// **nwritten**: -/// The number of bytes written. -#[inline] -pub unsafe fn fd_pwrite(fd_: fd, iovs_: &[ciovec], offset_: filesize, nwritten_: &mut usize) -> errno { - cloudabi_sys_fd_pwrite(fd_, iovs_.as_ptr(), iovs_.len(), offset_, nwritten_) -} - -/// Reads from a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor from which data should be -/// read. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be stored. -/// -/// **nread**: -/// The number of bytes read. -#[inline] -pub unsafe fn fd_read(fd_: fd, iovs_: &[iovec], nread_: &mut usize) -> errno { - cloudabi_sys_fd_read(fd_, iovs_.as_ptr(), iovs_.len(), nread_) -} - -/// Atomically replaces a file descriptor by a copy of another -/// file descriptor. -/// -/// Due to the strong focus on thread safety, this environment -/// does not provide a mechanism to duplicate a file descriptor to -/// an arbitrary number, like dup2(). This would be prone to race -/// conditions, as an actual file descriptor with the same number -/// could be allocated by a different thread at the same time. -/// -/// This system call provides a way to atomically replace file -/// descriptors, which would disappear if dup2() were to be -/// removed entirely. -/// -/// ## Parameters -/// -/// **from**: -/// The file descriptor that needs to be copied. -/// -/// **to**: -/// The file descriptor that needs to be -/// overwritten. -#[inline] -pub unsafe fn fd_replace(from_: fd, to_: fd) -> errno { - cloudabi_sys_fd_replace(from_, to_) -} - -/// Moves the offset of the file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose offset has to be -/// moved. -/// -/// **offset**: -/// The number of bytes to move. -/// -/// **whence**: -/// Relative to which position the move should -/// take place. -/// -/// **newoffset**: -/// The new offset of the file descriptor, -/// relative to the start of the file. -#[inline] -pub unsafe fn fd_seek(fd_: fd, offset_: filedelta, whence_: whence, newoffset_: &mut filesize) -> errno { - cloudabi_sys_fd_seek(fd_, offset_, whence_, newoffset_) -} - -/// Gets attributes of a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file descriptor's -/// attributes are stored. -#[inline] -pub unsafe fn fd_stat_get(fd_: fd, buf_: *mut fdstat) -> errno { - cloudabi_sys_fd_stat_get(fd_, buf_) -} - -/// Adjusts attributes of a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file descriptor -/// attributes that are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn fd_stat_put(fd_: fd, buf_: *const fdstat, flags_: fdsflags) -> errno { - cloudabi_sys_fd_stat_put(fd_, buf_, flags_) -} - -/// Synchronizes the data and metadata of a file to disk. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor of the file whose data -/// and metadata needs to be synchronized to disk. -#[inline] -pub unsafe fn fd_sync(fd_: fd) -> errno { - cloudabi_sys_fd_sync(fd_) -} - -/// Writes to a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor to which data should be -/// written. -/// -/// **iovs**: -/// List of scatter/gather vectors where data -/// should be retrieved. -/// -/// **nwritten**: -/// The number of bytes written. -#[inline] -pub unsafe fn fd_write(fd_: fd, iovs_: &[ciovec], nwritten_: &mut usize) -> errno { - cloudabi_sys_fd_write(fd_, iovs_.as_ptr(), iovs_.len(), nwritten_) -} - -/// Provides file advisory information on a file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor for which to provide file -/// advisory information. -/// -/// **offset**: -/// The offset within the file to which the -/// advisory applies. -/// -/// **len**: -/// The length of the region to which the advisory -/// applies. -/// -/// **advice**: -/// The advice. -#[inline] -pub unsafe fn file_advise(fd_: fd, offset_: filesize, len_: filesize, advice_: advice) -> errno { - cloudabi_sys_file_advise(fd_, offset_, len_, advice_) -} - -/// Forces the allocation of space in a file. -/// -/// ## Parameters -/// -/// **fd**: -/// The file in which the space should be -/// allocated. -/// -/// **offset**: -/// The offset at which the allocation should -/// start. -/// -/// **len**: -/// The length of the area that is allocated. -#[inline] -pub unsafe fn file_allocate(fd_: fd, offset_: filesize, len_: filesize) -> errno { - cloudabi_sys_file_allocate(fd_, offset_, len_) -} - -/// Creates a file of a specified type. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the file to be created starts. -/// -/// **path**: -/// The path at which the file should be created. -/// -/// **type**: -/// Possible values: -/// -/// - [`DIRECTORY`](enum.filetype.html#variant.DIRECTORY): -/// Creates a directory. -#[inline] -pub unsafe fn file_create(fd_: fd, path_: &[u8], type_: filetype) -> errno { - cloudabi_sys_file_create(fd_, path_.as_ptr(), path_.len(), type_) -} - -/// Creates a hard link. -/// -/// ## Parameters -/// -/// **fd1**: -/// The working directory at which the resolution -/// of the source path starts. -/// -/// **path1**: -/// The source path of the file that should be -/// hard linked. -/// -/// **fd2**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path at which the hard link -/// should be created. -#[inline] -pub unsafe fn file_link(fd1_: lookup, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { - cloudabi_sys_file_link(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) -} - -/// Opens a file. -/// -/// ## Parameters -/// -/// **dirfd**: -/// The working directory at which the resolution -/// of the file to be opened starts. -/// -/// **path**: -/// The path of the file that should be opened. -/// -/// **oflags**: -/// The method at which the file should be opened. -/// -/// **fds**: -/// [`fdstat.fs_rights_base`](struct.fdstat.html#structfield.fs_rights_base) and -/// [`fdstat.fs_rights_inheriting`](struct.fdstat.html#structfield.fs_rights_inheriting) specify the -/// initial rights of the newly created file -/// descriptor. The operating system is allowed to -/// return a file descriptor with fewer rights -/// than specified, if and only if those rights do -/// not apply to the type of file being opened. -/// -/// [`fdstat.fs_flags`](struct.fdstat.html#structfield.fs_flags) specifies the initial flags -/// of the file descriptor. -/// -/// [`fdstat.fs_filetype`](struct.fdstat.html#structfield.fs_filetype) is ignored. -/// -/// **fd**: -/// The file descriptor of the file that has been -/// opened. -#[inline] -pub unsafe fn file_open(dirfd_: lookup, path_: &[u8], oflags_: oflags, fds_: *const fdstat, fd_: &mut fd) -> errno { - cloudabi_sys_file_open(dirfd_, path_.as_ptr(), path_.len(), oflags_, fds_, fd_) -} - -/// Reads directory entries from a directory. -/// -/// When successful, the contents of the output buffer consist of -/// a sequence of directory entries. Each directory entry consists -/// of a [`dirent`](struct.dirent.html) object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes -/// holding the name of the directory entry. -/// -/// This system call fills the output buffer as much as possible, -/// potentially truncating the last directory entry. This allows -/// the caller to grow its read buffer size in case it's too small -/// to fit a single large directory entry, or skip the oversized -/// directory entry. -/// -/// ## Parameters -/// -/// **fd**: -/// The directory from which to read the directory -/// entries. -/// -/// **buf**: -/// The buffer where directory entries are stored. -/// -/// **cookie**: -/// The location within the directory to start -/// reading. -/// -/// **bufused**: -/// The number of bytes stored in the read buffer. -/// If less than the size of the read buffer, the -/// end of the directory has been reached. -#[inline] -pub unsafe fn file_readdir(fd_: fd, buf_: &mut [u8], cookie_: dircookie, bufused_: &mut usize) -> errno { - cloudabi_sys_file_readdir(fd_, buf_.as_mut_ptr() as *mut (), buf_.len(), cookie_, bufused_) -} - -/// Reads the contents of a symbolic link. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path of the symbolic starts. -/// -/// **path**: -/// The path of the symbolic link whose contents -/// should be read. -/// -/// **buf**: -/// The buffer where the contents of the symbolic -/// link should be stored. -/// -/// **bufused**: -/// The number of bytes placed in the buffer. -#[inline] -pub unsafe fn file_readlink(fd_: fd, path_: &[u8], buf_: &mut [u8], bufused_: &mut usize) -> errno { - cloudabi_sys_file_readlink(fd_, path_.as_ptr(), path_.len(), buf_.as_mut_ptr(), buf_.len(), bufused_) -} - -/// Renames a file. -/// -/// ## Parameters -/// -/// **fd1**: -/// The working directory at which the resolution -/// of the source path starts. -/// -/// **path1**: -/// The source path of the file that should be -/// renamed. -/// -/// **fd2**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path to which the file should -/// be renamed. -#[inline] -pub unsafe fn file_rename(fd1_: fd, path1_: &[u8], fd2_: fd, path2_: &[u8]) -> errno { - cloudabi_sys_file_rename(fd1_, path1_.as_ptr(), path1_.len(), fd2_, path2_.as_ptr(), path2_.len()) -} - -/// Gets attributes of a file by file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file's attributes are -/// stored. -#[inline] -pub unsafe fn file_stat_fget(fd_: fd, buf_: *mut filestat) -> errno { - cloudabi_sys_file_stat_fget(fd_, buf_) -} - -/// Adjusts attributes of a file by file descriptor. -/// -/// ## Parameters -/// -/// **fd**: -/// The file descriptor whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file attributes that -/// are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn file_stat_fput(fd_: fd, buf_: *const filestat, flags_: fsflags) -> errno { - cloudabi_sys_file_stat_fput(fd_, buf_, flags_) -} - -/// Gets attributes of a file by path. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path whose attributes have to be -/// obtained starts. -/// -/// **path**: -/// The path of the file whose attributes have to -/// be obtained. -/// -/// **buf**: -/// The buffer where the file's attributes are -/// stored. -#[inline] -pub unsafe fn file_stat_get(fd_: lookup, path_: &[u8], buf_: *mut filestat) -> errno { - cloudabi_sys_file_stat_get(fd_, path_.as_ptr(), path_.len(), buf_) -} - -/// Adjusts attributes of a file by path. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path whose attributes have to be -/// adjusted starts. -/// -/// **path**: -/// The path of the file whose attributes have to -/// be adjusted. -/// -/// **buf**: -/// The desired values of the file attributes that -/// are adjusted. -/// -/// **flags**: -/// A bitmask indicating which attributes have to -/// be adjusted. -#[inline] -pub unsafe fn file_stat_put(fd_: lookup, path_: &[u8], buf_: *const filestat, flags_: fsflags) -> errno { - cloudabi_sys_file_stat_put(fd_, path_.as_ptr(), path_.len(), buf_, flags_) -} - -/// Creates a symbolic link. -/// -/// ## Parameters -/// -/// **path1**: -/// The contents of the symbolic link. -/// -/// **fd**: -/// The working directory at which the resolution -/// of the destination path starts. -/// -/// **path2**: -/// The destination path at which the symbolic -/// link should be created. -#[inline] -pub unsafe fn file_symlink(path1_: &[u8], fd_: fd, path2_: &[u8]) -> errno { - cloudabi_sys_file_symlink(path1_.as_ptr(), path1_.len(), fd_, path2_.as_ptr(), path2_.len()) -} - -/// Unlinks a file, or removes a directory. -/// -/// ## Parameters -/// -/// **fd**: -/// The working directory at which the resolution -/// of the path starts. -/// -/// **path**: -/// The path that needs to be unlinked or removed. -/// -/// **flags**: -/// Possible values: -/// -/// - [`REMOVEDIR`](struct.ulflags.html#associatedconstant.REMOVEDIR): -/// If set, attempt to remove a directory. -/// Otherwise, unlink a file. -#[inline] -pub unsafe fn file_unlink(fd_: fd, path_: &[u8], flags_: ulflags) -> errno { - cloudabi_sys_file_unlink(fd_, path_.as_ptr(), path_.len(), flags_) -} - -/// Unlocks a write-locked userspace lock. -/// -/// If a userspace lock is unlocked while having its -/// [`LOCK_KERNEL_MANAGED`](constant.LOCK_KERNEL_MANAGED.html) flag set, the lock cannot be unlocked in -/// userspace directly. This system call needs to be performed -/// instead, so that any waiting threads can be woken up. -/// -/// To prevent spurious invocations of this system call, the lock -/// must be locked for writing. This prevents other threads from -/// acquiring additional read locks while the system call is in -/// progress. If the lock is acquired for reading, it must first -/// be upgraded to a write lock. -/// -/// ## Parameters -/// -/// **lock**: -/// The userspace lock that is locked for writing -/// by the calling thread. -/// -/// **scope**: -/// Whether the lock is stored in private or -/// shared memory. -#[inline] -pub unsafe fn lock_unlock(lock_: *mut lock, scope_: scope) -> errno { - cloudabi_sys_lock_unlock(lock_, scope_) -} - -/// Provides memory advisory information on a region of memory. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages for which to provide memory advisory -/// information. -/// -/// **advice**: -/// The advice. -#[inline] -pub unsafe fn mem_advise(mapping_: &mut [u8], advice_: advice) -> errno { - cloudabi_sys_mem_advise(mapping_.as_mut_ptr() as *mut (), mapping_.len(), advice_) -} - -/// Creates a memory mapping, making the contents of a file -/// accessible through memory. -/// -/// ## Parameters -/// -/// **addr**: -/// If [`FIXED`](struct.mflags.html#associatedconstant.FIXED) is set, specifies to which -/// address the file region is mapped. Otherwise, -/// the mapping is performed at an unused -/// location. -/// -/// **len**: -/// The length of the memory mapping to be -/// created. -/// -/// **prot**: -/// Initial memory protection options for the -/// memory mapping. -/// -/// **flags**: -/// Memory mapping flags. -/// -/// **fd**: -/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be -/// [`MAP_ANON_FD`](constant.MAP_ANON_FD.html). Otherwise, this argument -/// specifies the file whose contents need to be -/// mapped. -/// -/// **off**: -/// If [`ANON`](struct.mflags.html#associatedconstant.ANON) is set, this argument must be -/// zero. Otherwise, this argument specifies the -/// offset within the file at which the mapping -/// starts. -/// -/// **mem**: -/// The starting address of the memory mapping. -#[inline] -pub unsafe fn mem_map(addr_: *mut (), len_: usize, prot_: mprot, flags_: mflags, fd_: fd, off_: filesize, mem_: &mut *mut ()) -> errno { - cloudabi_sys_mem_map(addr_, len_, prot_, flags_, fd_, off_, mem_) -} - -/// Change the protection of a memory mapping. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that need their protection changed. -/// -/// **prot**: -/// New protection options. -#[inline] -pub unsafe fn mem_protect(mapping_: &mut [u8], prot_: mprot) -> errno { - cloudabi_sys_mem_protect(mapping_.as_mut_ptr() as *mut (), mapping_.len(), prot_) -} - -/// Synchronize a region of memory with its physical storage. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that need to be synchronized. -/// -/// **flags**: -/// The method of synchronization. -#[inline] -pub unsafe fn mem_sync(mapping_: &mut [u8], flags_: msflags) -> errno { - cloudabi_sys_mem_sync(mapping_.as_mut_ptr() as *mut (), mapping_.len(), flags_) -} - -/// Unmaps a region of memory. -/// -/// ## Parameters -/// -/// **mapping**: -/// The pages that needs to be unmapped. -#[inline] -pub unsafe fn mem_unmap(mapping_: &mut [u8]) -> errno { - cloudabi_sys_mem_unmap(mapping_.as_mut_ptr() as *mut (), mapping_.len()) -} - -/// Concurrently polls for the occurrence of a set of events. -/// -/// ## Parameters -/// -/// **in**: -/// The events to which to subscribe. -/// -/// **out**: -/// The events that have occurred. -/// -/// **nsubscriptions**: -/// Both the number of subscriptions and events. -/// -/// **nevents**: -/// The number of events stored. -#[inline] -pub unsafe fn poll(in_: *const subscription, out_: *mut event, nsubscriptions_: usize, nevents_: &mut usize) -> errno { - cloudabi_sys_poll(in_, out_, nsubscriptions_, nevents_) -} - -/// Replaces the process by a new executable. -/// -/// Process execution in CloudABI differs from POSIX in two ways: -/// handling of arguments and inheritance of file descriptors. -/// -/// CloudABI does not use string command line arguments. Instead, -/// a buffer with binary data is copied into the address space of -/// the new executable. The kernel does not enforce any specific -/// structure to this data, although CloudABI's C library uses it -/// to store a tree structure that is semantically identical to -/// YAML. -/// -/// Due to the strong focus on thread safety, file descriptors -/// aren't inherited through close-on-exec flags. An explicit -/// list of file descriptors that need to be retained needs to be -/// provided. After execution, file descriptors are placed in the -/// order in which they are stored in the array. This not only -/// makes the execution process deterministic. It also prevents -/// potential information disclosures about the layout of the -/// original process. -/// -/// ## Parameters -/// -/// **fd**: -/// A file descriptor of the new executable. -/// -/// **data**: -/// Binary argument data that is passed on to the -/// new executable. -/// -/// **fds**: -/// The layout of the file descriptor table after -/// execution. -#[inline] -pub unsafe fn proc_exec(fd_: fd, data_: &[u8], fds_: &[fd]) -> errno { - cloudabi_sys_proc_exec(fd_, data_.as_ptr() as *const (), data_.len(), fds_.as_ptr(), fds_.len()) -} - -/// Terminates the process normally. -/// -/// ## Parameters -/// -/// **rval**: -/// The exit code returned by the process. The -/// exit code can be obtained by other processes -/// through [`event.union.proc_terminate.exitcode`](struct.event_proc_terminate.html#structfield.exitcode). -#[inline] -pub unsafe fn proc_exit(rval_: exitcode) -> ! { - cloudabi_sys_proc_exit(rval_) -} - -/// Forks the process of the calling thread. -/// -/// After forking, a new process shall be created, having only a -/// copy of the calling thread. The parent process will obtain a -/// process descriptor. When closed, the child process is -/// automatically signaled with [`KILL`](enum.signal.html#variant.KILL). -/// -/// ## Parameters -/// -/// **fd**: -/// In the parent process: the file descriptor -/// number of the process descriptor. -/// -/// In the child process: [`PROCESS_CHILD`](constant.PROCESS_CHILD.html). -/// -/// **tid**: -/// In the parent process: undefined. -/// -/// In the child process: the thread ID of the -/// initial thread of the child process. -#[inline] -pub unsafe fn proc_fork(fd_: &mut fd, tid_: &mut tid) -> errno { - cloudabi_sys_proc_fork(fd_, tid_) -} - -/// Sends a signal to the process of the calling thread. -/// -/// ## Parameters -/// -/// **sig**: -/// The signal condition that should be triggered. -/// If the signal causes the process to terminate, -/// its condition can be obtained by other -/// processes through -/// [`event.union.proc_terminate.signal`](struct.event_proc_terminate.html#structfield.signal). -#[inline] -pub unsafe fn proc_raise(sig_: signal) -> errno { - cloudabi_sys_proc_raise(sig_) -} - -/// Obtains random data from the kernel random number generator. -/// -/// As this interface is not guaranteed to be fast, it is advised -/// that the random data obtained through this system call is used -/// as the seed for a userspace pseudo-random number generator. -/// -/// ## Parameters -/// -/// **buf**: -/// The buffer that needs to be filled with random -/// data. -#[inline] -pub unsafe fn random_get(buf_: &mut [u8]) -> errno { - cloudabi_sys_random_get(buf_.as_mut_ptr() as *mut (), buf_.len()) -} - -/// Receives a message on a socket. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket on which a message should be -/// received. -/// -/// **in**: -/// Input parameters. -/// -/// **out**: -/// Output parameters. -#[inline] -pub unsafe fn sock_recv(sock_: fd, in_: *const recv_in, out_: *mut recv_out) -> errno { - cloudabi_sys_sock_recv(sock_, in_, out_) -} - -/// Sends a message on a socket. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket on which a message should be sent. -/// -/// **in**: -/// Input parameters. -/// -/// **out**: -/// Output parameters. -#[inline] -pub unsafe fn sock_send(sock_: fd, in_: *const send_in, out_: *mut send_out) -> errno { - cloudabi_sys_sock_send(sock_, in_, out_) -} - -/// Shuts down socket send and receive channels. -/// -/// ## Parameters -/// -/// **sock**: -/// The socket that needs its channels shut down. -/// -/// **how**: -/// Which channels on the socket need to be shut -/// down. -#[inline] -pub unsafe fn sock_shutdown(sock_: fd, how_: sdflags) -> errno { - cloudabi_sys_sock_shutdown(sock_, how_) -} - -/// Creates a new thread within the current process. -/// -/// ## Parameters -/// -/// **attr**: -/// The desired attributes of the new thread. -/// -/// **tid**: -/// The thread ID of the new thread. -#[inline] -pub unsafe fn thread_create(attr_: *mut threadattr, tid_: &mut tid) -> errno { - cloudabi_sys_thread_create(attr_, tid_) -} - -/// Terminates the calling thread. -/// -/// This system call can also unlock a single userspace lock -/// after termination, which can be used to implement thread -/// joining. -/// -/// ## Parameters -/// -/// **lock**: -/// Userspace lock that is locked for writing by -/// the calling thread. -/// -/// **scope**: -/// Whether the lock is stored in private or -/// shared memory. -#[inline] -pub unsafe fn thread_exit(lock_: *mut lock, scope_: scope) -> ! { - cloudabi_sys_thread_exit(lock_, scope_) -} - -/// Temporarily yields execution of the calling thread. -#[inline] -pub unsafe fn thread_yield() -> errno { - cloudabi_sys_thread_yield() -} diff --git a/third_party/cargo/vendor/cmake-0.1.44/.cargo-checksum.json b/third_party/cargo/vendor/cmake-0.1.44/.cargo-checksum.json deleted file mode 100644 index e0e1595..0000000 --- a/third_party/cargo/vendor/cmake-0.1.44/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"0ce2c3999bc31b6e8fc5356e19c32f950e6176638aa2834c5b0d00c6c58397a0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"a4ad0b734acb4d50db72782207587552c5e33c52500318c202776cd32dbdea4a","src/lib.rs":"45127eb441cee715f4337cfac78c9ce8ec8feb167d2814ff11a6708a9533bde7"},"package":"0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cmake-0.1.44/BUILD.bazel b/third_party/cargo/vendor/cmake-0.1.44/BUILD.bazel deleted file mode 100644 index fd1e01c..0000000 --- a/third_party/cargo/vendor/cmake-0.1.44/BUILD.bazel +++ /dev/null @@ -1,54 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "cmake", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.1.44", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/cc-1.0.54:cc", - ], -) diff --git a/third_party/cargo/vendor/cmake-0.1.44/Cargo.toml b/third_party/cargo/vendor/cmake-0.1.44/Cargo.toml deleted file mode 100644 index cc5c482..0000000 --- a/third_party/cargo/vendor/cmake-0.1.44/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "cmake" -version = "0.1.44" -authors = ["Alex Crichton "] -description = "A build dependency for running `cmake` to build a native library\n" -homepage = "https://github.com/alexcrichton/cmake-rs" -documentation = "https://docs.rs/cmake" -readme = "README.md" -keywords = ["build-dependencies"] -categories = ["development-tools::build-utils"] -license = "MIT/Apache-2.0" -repository = "https://github.com/alexcrichton/cmake-rs" -[dependencies.cc] -version = "1.0.41" diff --git a/third_party/cargo/vendor/cmake-0.1.44/README.md b/third_party/cargo/vendor/cmake-0.1.44/README.md deleted file mode 100644 index 7ef49ca..0000000 --- a/third_party/cargo/vendor/cmake-0.1.44/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# cmake - -[Documentation](https://docs.rs/cmake) - -A build dependency for running the `cmake` build tool to compile a native -library. - -```toml -# Cargo.toml -[build-dependencies] -cmake = "0.1" -``` - -The CMake executable is assumed to be `cmake` unless the `CMAKE` -environmental variable is set. - -# License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in cmake by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/cmake-0.1.44/src/lib.rs b/third_party/cargo/vendor/cmake-0.1.44/src/lib.rs deleted file mode 100644 index ae8770f..0000000 --- a/third_party/cargo/vendor/cmake-0.1.44/src/lib.rs +++ /dev/null @@ -1,886 +0,0 @@ -//! A build dependency for running `cmake` to build a native library -//! -//! This crate provides some necessary boilerplate and shim support for running -//! the system `cmake` command to build a native library. It will add -//! appropriate cflags for building code to link into Rust, handle cross -//! compilation, and use the necessary generator for the platform being -//! targeted. -//! -//! The builder-style configuration allows for various variables and such to be -//! passed down into the build as well. -//! -//! ## Installation -//! -//! Add this to your `Cargo.toml`: -//! -//! ```toml -//! [build-dependencies] -//! cmake = "0.1" -//! ``` -//! -//! ## Examples -//! -//! ```no_run -//! use cmake; -//! -//! // Builds the project in the directory located in `libfoo`, installing it -//! // into $OUT_DIR -//! let dst = cmake::build("libfoo"); -//! -//! println!("cargo:rustc-link-search=native={}", dst.display()); -//! println!("cargo:rustc-link-lib=static=foo"); -//! ``` -//! -//! ```no_run -//! use cmake::Config; -//! -//! let dst = Config::new("libfoo") -//! .define("FOO", "BAR") -//! .cflag("-foo") -//! .build(); -//! println!("cargo:rustc-link-search=native={}", dst.display()); -//! println!("cargo:rustc-link-lib=static=foo"); -//! ``` - -#![deny(missing_docs)] - -extern crate cc; - -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fs::{self, File}; -use std::io::prelude::*; -use std::io::ErrorKind; -use std::path::{Path, PathBuf}; -use std::process::Command; - -/// Builder style configuration for a pending CMake build. -pub struct Config { - path: PathBuf, - generator: Option, - cflags: OsString, - cxxflags: OsString, - asmflags: OsString, - defines: Vec<(OsString, OsString)>, - deps: Vec, - target: Option, - host: Option, - out_dir: Option, - profile: Option, - build_args: Vec, - cmake_target: Option, - env: Vec<(OsString, OsString)>, - static_crt: Option, - uses_cxx11: bool, - always_configure: bool, - no_build_target: bool, - verbose_cmake: bool, - verbose_make: bool, - pic: Option, -} - -/// Builds the native library rooted at `path` with the default cmake options. -/// This will return the directory in which the library was installed. -/// -/// # Examples -/// -/// ```no_run -/// use cmake; -/// -/// // Builds the project in the directory located in `libfoo`, installing it -/// // into $OUT_DIR -/// let dst = cmake::build("libfoo"); -/// -/// println!("cargo:rustc-link-search=native={}", dst.display()); -/// println!("cargo:rustc-link-lib=static=foo"); -/// ``` -/// -pub fn build>(path: P) -> PathBuf { - Config::new(path.as_ref()).build() -} - -impl Config { - /// Creates a new blank set of configuration to build the project specified - /// at the path `path`. - pub fn new>(path: P) -> Config { - Config { - path: env::current_dir().unwrap().join(path), - generator: None, - cflags: OsString::new(), - cxxflags: OsString::new(), - asmflags: OsString::new(), - defines: Vec::new(), - deps: Vec::new(), - profile: None, - out_dir: None, - target: None, - host: None, - build_args: Vec::new(), - cmake_target: None, - env: Vec::new(), - static_crt: None, - uses_cxx11: false, - always_configure: true, - no_build_target: false, - verbose_cmake: false, - verbose_make: false, - pic: None, - } - } - - /// Sets flag for PIC. Otherwise use cc::Build platform default - pub fn pic(&mut self, explicit_flag: bool) -> &mut Config { - self.pic = Some(explicit_flag); - self - } - - /// Sets the build-tool generator (`-G`) for this compilation. - pub fn generator>(&mut self, generator: T) -> &mut Config { - self.generator = Some(generator.as_ref().to_owned()); - self - } - - /// Adds a custom flag to pass down to the C compiler, supplementing those - /// that this library already passes. - pub fn cflag>(&mut self, flag: P) -> &mut Config { - self.cflags.push(" "); - self.cflags.push(flag.as_ref()); - self - } - - /// Adds a custom flag to pass down to the C++ compiler, supplementing those - /// that this library already passes. - pub fn cxxflag>(&mut self, flag: P) -> &mut Config { - self.cxxflags.push(" "); - self.cxxflags.push(flag.as_ref()); - self - } - - /// Adds a custom flag to pass down to the ASM compiler, supplementing those - /// that this library already passes. - pub fn asmflag>(&mut self, flag: P) -> &mut Config { - self.asmflags.push(" "); - self.asmflags.push(flag.as_ref()); - self - } - - /// Adds a new `-D` flag to pass to cmake during the generation step. - pub fn define(&mut self, k: K, v: V) -> &mut Config - where - K: AsRef, - V: AsRef, - { - self.defines - .push((k.as_ref().to_owned(), v.as_ref().to_owned())); - self - } - - /// Registers a dependency for this compilation on the native library built - /// by Cargo previously. - /// - /// This registration will modify the `CMAKE_PREFIX_PATH` environment - /// variable for the build system generation step. - pub fn register_dep(&mut self, dep: &str) -> &mut Config { - self.deps.push(dep.to_string()); - self - } - - /// Sets the target triple for this compilation. - /// - /// This is automatically scraped from `$TARGET` which is set for Cargo - /// build scripts so it's not necessary to call this from a build script. - pub fn target(&mut self, target: &str) -> &mut Config { - self.target = Some(target.to_string()); - self - } - - /// Disables the cmake target option for this compilation. - /// - /// Note that this isn't related to the target triple passed to the compiler! - pub fn no_build_target(&mut self, no_build_target: bool) -> &mut Config { - self.no_build_target = no_build_target; - self - } - - /// Sets the host triple for this compilation. - /// - /// This is automatically scraped from `$HOST` which is set for Cargo - /// build scripts so it's not necessary to call this from a build script. - pub fn host(&mut self, host: &str) -> &mut Config { - self.host = Some(host.to_string()); - self - } - - /// Sets the output directory for this compilation. - /// - /// This is automatically scraped from `$OUT_DIR` which is set for Cargo - /// build scripts so it's not necessary to call this from a build script. - pub fn out_dir>(&mut self, out: P) -> &mut Config { - self.out_dir = Some(out.as_ref().to_path_buf()); - self - } - - /// Sets the `CMAKE_BUILD_TYPE=build_type` variable. - /// - /// By default, this value is automatically inferred from Rust's compilation - /// profile as follows: - /// - /// * if `opt-level=0` then `CMAKE_BUILD_TYPE=Debug`, - /// * if `opt-level={1,2,3}` and: - /// * `debug=false` then `CMAKE_BUILD_TYPE=Release` - /// * otherwise `CMAKE_BUILD_TYPE=RelWithDebInfo` - /// * if `opt-level={s,z}` then `CMAKE_BUILD_TYPE=MinSizeRel` - pub fn profile(&mut self, profile: &str) -> &mut Config { - self.profile = Some(profile.to_string()); - self - } - - /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. - /// - /// This option defaults to `false`, and affect only msvc targets. - pub fn static_crt(&mut self, static_crt: bool) -> &mut Config { - self.static_crt = Some(static_crt); - self - } - - /// Add an argument to the final `cmake` build step - pub fn build_arg>(&mut self, arg: A) -> &mut Config { - self.build_args.push(arg.as_ref().to_owned()); - self - } - - /// Configure an environment variable for the `cmake` processes spawned by - /// this crate in the `build` step. - pub fn env(&mut self, key: K, value: V) -> &mut Config - where - K: AsRef, - V: AsRef, - { - self.env - .push((key.as_ref().to_owned(), value.as_ref().to_owned())); - self - } - - /// Sets the build target for the final `cmake` build step, this will - /// default to "install" if not specified. - pub fn build_target(&mut self, target: &str) -> &mut Config { - self.cmake_target = Some(target.to_string()); - self - } - - /// Alters the default target triple on OSX to ensure that c++11 is - /// available. Does not change the target triple if it is explicitly - /// specified. - /// - /// This does not otherwise affect any CXX flags, i.e. it does not set - /// -std=c++11 or -stdlib=libc++. - pub fn uses_cxx11(&mut self) -> &mut Config { - self.uses_cxx11 = true; - self - } - - /// Forces CMake to always run before building the custom target. - /// - /// In some cases, when you have a big project, you can disable - /// subsequents runs of cmake to make `cargo build` faster. - pub fn always_configure(&mut self, always_configure: bool) -> &mut Config { - self.always_configure = always_configure; - self - } - - /// Sets very verbose output. - pub fn very_verbose(&mut self, value: bool) -> &mut Config { - self.verbose_cmake = value; - self.verbose_make = value; - self - } - - // Simple heuristic to determine if we're cross-compiling using the Android - // NDK toolchain file. - fn uses_android_ndk(&self) -> bool { - // `ANDROID_ABI` is the only required flag: - // https://developer.android.com/ndk/guides/cmake#android_abi - self.defined("ANDROID_ABI") - && self.defines.iter().any(|(flag, value)| { - flag == "CMAKE_TOOLCHAIN_FILE" - && Path::new(value).file_name() == Some("android.toolchain.cmake".as_ref()) - }) - } - - /// Run this configuration, compiling the library with all the configured - /// options. - /// - /// This will run both the build system generator command as well as the - /// command to build the library. - pub fn build(&mut self) -> PathBuf { - let target = match self.target.clone() { - Some(t) => t, - None => { - let mut t = getenv_unwrap("TARGET"); - if t.ends_with("-darwin") && self.uses_cxx11 { - t = t + "11" - } - t - } - }; - let host = self.host.clone().unwrap_or_else(|| getenv_unwrap("HOST")); - let msvc = target.contains("msvc"); - let ndk = self.uses_android_ndk(); - let mut c_cfg = cc::Build::new(); - c_cfg - .cargo_metadata(false) - .opt_level(0) - .debug(false) - .warnings(false) - .host(&host) - .no_default_flags(ndk); - if !ndk { - c_cfg.target(&target); - } - let mut cxx_cfg = cc::Build::new(); - cxx_cfg - .cargo_metadata(false) - .cpp(true) - .opt_level(0) - .debug(false) - .warnings(false) - .host(&host) - .no_default_flags(ndk); - if !ndk { - cxx_cfg.target(&target); - } - if let Some(static_crt) = self.static_crt { - c_cfg.static_crt(static_crt); - cxx_cfg.static_crt(static_crt); - } - if let Some(explicit_flag) = self.pic { - c_cfg.pic(explicit_flag); - cxx_cfg.pic(explicit_flag); - } - let c_compiler = c_cfg.get_compiler(); - let cxx_compiler = cxx_cfg.get_compiler(); - let asm_compiler = c_cfg.get_compiler(); - - let dst = self - .out_dir - .clone() - .unwrap_or_else(|| PathBuf::from(getenv_unwrap("OUT_DIR"))); - let build = dst.join("build"); - self.maybe_clear(&build); - let _ = fs::create_dir(&build); - - // Add all our dependencies to our cmake paths - let mut cmake_prefix_path = Vec::new(); - for dep in &self.deps { - let dep = dep.to_uppercase().replace('-', "_"); - if let Some(root) = env::var_os(&format!("DEP_{}_ROOT", dep)) { - cmake_prefix_path.push(PathBuf::from(root)); - } - } - let system_prefix = env::var_os("CMAKE_PREFIX_PATH").unwrap_or(OsString::new()); - cmake_prefix_path.extend(env::split_paths(&system_prefix).map(|s| s.to_owned())); - let cmake_prefix_path = env::join_paths(&cmake_prefix_path).unwrap(); - - // Build up the first cmake command to build the build system. - let executable = env::var("CMAKE").unwrap_or("cmake".to_owned()); - let mut cmd = Command::new(&executable); - - if self.verbose_cmake { - cmd.arg("-Wdev"); - cmd.arg("--debug-output"); - } - - cmd.arg(&self.path).current_dir(&build); - let mut is_ninja = false; - if let Some(ref generator) = self.generator { - is_ninja = generator.to_string_lossy().contains("Ninja"); - } - if target.contains("windows-gnu") { - if host.contains("windows") { - // On MinGW we need to coerce cmake to not generate a visual - // studio build system but instead use makefiles that MinGW can - // use to build. - if self.generator.is_none() { - // If make.exe isn't found, that means we may be using a MinGW - // toolchain instead of a MSYS2 toolchain. If neither is found, - // the build cannot continue. - let has_msys2 = Command::new("make") - .arg("--version") - .output() - .err() - .map(|e| e.kind() != ErrorKind::NotFound) - .unwrap_or(true); - let has_mingw32 = Command::new("mingw32-make") - .arg("--version") - .output() - .err() - .map(|e| e.kind() != ErrorKind::NotFound) - .unwrap_or(true); - - let generator = match (has_msys2, has_mingw32) { - (true, _) => "MSYS Makefiles", - (false, true) => "MinGW Makefiles", - (false, false) => fail("no valid generator found for GNU toolchain; MSYS or MinGW must be installed") - }; - - cmd.arg("-G").arg(generator); - } - } else { - // If we're cross compiling onto windows, then set some - // variables which will hopefully get things to succeed. Some - // systems may need the `windres` or `dlltool` variables set, so - // set them if possible. - if !self.defined("CMAKE_SYSTEM_NAME") { - cmd.arg("-DCMAKE_SYSTEM_NAME=Windows"); - } - if !self.defined("CMAKE_RC_COMPILER") { - let exe = find_exe(c_compiler.path()); - if let Some(name) = exe.file_name().unwrap().to_str() { - let name = name.replace("gcc", "windres"); - let windres = exe.with_file_name(name); - if windres.is_file() { - let mut arg = OsString::from("-DCMAKE_RC_COMPILER="); - arg.push(&windres); - cmd.arg(arg); - } - } - } - } - } else if msvc { - // If we're on MSVC we need to be sure to use the right generator or - // otherwise we won't get 32/64 bit correct automatically. - // This also guarantees that NMake generator isn't chosen implicitly. - let using_nmake_generator; - if self.generator.is_none() { - cmd.arg("-G").arg(self.visual_studio_generator(&target)); - using_nmake_generator = false; - } else { - using_nmake_generator = self.generator.as_ref().unwrap() == "NMake Makefiles"; - } - if !is_ninja && !using_nmake_generator { - if target.contains("x86_64") { - cmd.arg("-Thost=x64"); - cmd.arg("-Ax64"); - } else if target.contains("thumbv7a") { - cmd.arg("-Thost=x64"); - cmd.arg("-Aarm"); - } else if target.contains("aarch64") { - cmd.arg("-Thost=x64"); - cmd.arg("-AARM64"); - } else if target.contains("i686") { - use cc::windows_registry::{find_vs_version, VsVers}; - match find_vs_version() { - Ok(VsVers::Vs16) => { - // 32-bit x86 toolset used to be the default for all hosts, - // but Visual Studio 2019 changed the default toolset to match the host, - // so we need to manually override it for x86 targets - cmd.arg("-Thost=x86"); - cmd.arg("-AWin32"); - } - _ => {} - }; - } else { - panic!("unsupported msvc target: {}", target); - } - } - } else if target.contains("redox") { - if !self.defined("CMAKE_SYSTEM_NAME") { - cmd.arg("-DCMAKE_SYSTEM_NAME=Generic"); - } - } else if target.contains("solaris") { - if !self.defined("CMAKE_SYSTEM_NAME") { - cmd.arg("-DCMAKE_SYSTEM_NAME=SunOS"); - } - } - if let Some(ref generator) = self.generator { - cmd.arg("-G").arg(generator); - } - let profile = self.profile.clone().unwrap_or_else(|| { - // Automatically set the `CMAKE_BUILD_TYPE` if the user did not - // specify one. - - // Determine Rust's profile, optimization level, and debug info: - #[derive(PartialEq)] - enum RustProfile { - Debug, - Release, - } - #[derive(PartialEq, Debug)] - enum OptLevel { - Debug, - Release, - Size, - } - - let rust_profile = match &getenv_unwrap("PROFILE")[..] { - "debug" => RustProfile::Debug, - "release" | "bench" => RustProfile::Release, - unknown => { - eprintln!( - "Warning: unknown Rust profile={}; defaulting to a release build.", - unknown - ); - RustProfile::Release - } - }; - - let opt_level = match &getenv_unwrap("OPT_LEVEL")[..] { - "0" => OptLevel::Debug, - "1" | "2" | "3" => OptLevel::Release, - "s" | "z" => OptLevel::Size, - unknown => { - let default_opt_level = match rust_profile { - RustProfile::Debug => OptLevel::Debug, - RustProfile::Release => OptLevel::Release, - }; - eprintln!( - "Warning: unknown opt-level={}; defaulting to a {:?} build.", - unknown, default_opt_level - ); - default_opt_level - } - }; - - let debug_info: bool = match &getenv_unwrap("DEBUG")[..] { - "false" => false, - "true" => true, - unknown => { - eprintln!("Warning: unknown debug={}; defaulting to `true`.", unknown); - true - } - }; - - match (opt_level, debug_info) { - (OptLevel::Debug, _) => "Debug", - (OptLevel::Release, false) => "Release", - (OptLevel::Release, true) => "RelWithDebInfo", - (OptLevel::Size, _) => "MinSizeRel", - } - .to_string() - }); - for &(ref k, ref v) in &self.defines { - let mut os = OsString::from("-D"); - os.push(k); - os.push("="); - os.push(v); - cmd.arg(os); - } - - if !self.defined("CMAKE_INSTALL_PREFIX") { - let mut dstflag = OsString::from("-DCMAKE_INSTALL_PREFIX="); - dstflag.push(&dst); - cmd.arg(dstflag); - } - - let build_type = self - .defines - .iter() - .find(|&&(ref a, _)| a == "CMAKE_BUILD_TYPE") - .map(|x| x.1.to_str().unwrap()) - .unwrap_or(&profile); - let build_type_upcase = build_type - .chars() - .flat_map(|c| c.to_uppercase()) - .collect::(); - - { - // let cmake deal with optimization/debuginfo - let skip_arg = |arg: &OsStr| match arg.to_str() { - Some(s) => s.starts_with("-O") || s.starts_with("/O") || s == "-g", - None => false, - }; - let mut set_compiler = |kind: &str, compiler: &cc::Tool, extra: &OsString| { - let flag_var = format!("CMAKE_{}_FLAGS", kind); - let tool_var = format!("CMAKE_{}_COMPILER", kind); - if !self.defined(&flag_var) { - let mut flagsflag = OsString::from("-D"); - flagsflag.push(&flag_var); - flagsflag.push("="); - flagsflag.push(extra); - for arg in compiler.args() { - if skip_arg(arg) { - continue; - } - flagsflag.push(" "); - flagsflag.push(arg); - } - cmd.arg(flagsflag); - } - - // The visual studio generator apparently doesn't respect - // `CMAKE_C_FLAGS` but does respect `CMAKE_C_FLAGS_RELEASE` and - // such. We need to communicate /MD vs /MT, so set those vars - // here. - // - // Note that for other generators, though, this *overrides* - // things like the optimization flags, which is bad. - if self.generator.is_none() && msvc { - let flag_var_alt = format!("CMAKE_{}_FLAGS_{}", kind, build_type_upcase); - if !self.defined(&flag_var_alt) { - let mut flagsflag = OsString::from("-D"); - flagsflag.push(&flag_var_alt); - flagsflag.push("="); - flagsflag.push(extra); - for arg in compiler.args() { - if skip_arg(arg) { - continue; - } - flagsflag.push(" "); - flagsflag.push(arg); - } - cmd.arg(flagsflag); - } - } - - // Apparently cmake likes to have an absolute path to the - // compiler as otherwise it sometimes thinks that this variable - // changed as it thinks the found compiler, /usr/bin/cc, - // differs from the specified compiler, cc. Not entirely sure - // what's up, but at least this means cmake doesn't get - // confused? - // - // Also specify this on Windows only if we use MSVC with Ninja, - // as it's not needed for MSVC with Visual Studio generators and - // for MinGW it doesn't really vary. - if !self.defined("CMAKE_TOOLCHAIN_FILE") - && !self.defined(&tool_var) - && (env::consts::FAMILY != "windows" || (msvc && is_ninja)) - { - let mut ccompiler = OsString::from("-D"); - ccompiler.push(&tool_var); - ccompiler.push("="); - ccompiler.push(find_exe(compiler.path())); - #[cfg(windows)] - { - // CMake doesn't like unescaped `\`s in compiler paths - // so we either have to escape them or replace with `/`s. - use std::os::windows::ffi::{OsStrExt, OsStringExt}; - let wchars = ccompiler - .encode_wide() - .map(|wchar| { - if wchar == b'\\' as u16 { - '/' as u16 - } else { - wchar - } - }) - .collect::>(); - ccompiler = OsString::from_wide(&wchars); - } - cmd.arg(ccompiler); - } - }; - - set_compiler("C", &c_compiler, &self.cflags); - set_compiler("CXX", &cxx_compiler, &self.cxxflags); - set_compiler("ASM", &asm_compiler, &self.asmflags); - } - - if !self.defined("CMAKE_BUILD_TYPE") { - cmd.arg(&format!("-DCMAKE_BUILD_TYPE={}", profile)); - } - - if self.verbose_make { - cmd.arg("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON"); - } - - if !self.defined("CMAKE_TOOLCHAIN_FILE") { - if let Ok(s) = env::var("CMAKE_TOOLCHAIN_FILE") { - cmd.arg(&format!("-DCMAKE_TOOLCHAIN_FILE={}", s)); - } - } - - for &(ref k, ref v) in c_compiler.env().iter().chain(&self.env) { - cmd.env(k, v); - } - - if self.always_configure || !build.join("CMakeCache.txt").exists() { - run(cmd.env("CMAKE_PREFIX_PATH", cmake_prefix_path), "cmake"); - } else { - println!("CMake project was already configured. Skipping configuration step."); - } - - let mut makeflags = None; - let mut parallel_flags = None; - - if let Ok(s) = env::var("NUM_JOBS") { - match self.generator.as_ref().map(|g| g.to_string_lossy()) { - Some(ref g) if g.contains("Ninja") => { - parallel_flags = Some(format!("-j{}", s)); - } - Some(ref g) if g.contains("Visual Studio") => { - parallel_flags = Some(format!("/m:{}", s)); - } - Some(ref g) if g.contains("NMake") => { - // NMake creates `Makefile`s, but doesn't understand `-jN`. - } - _ if fs::metadata(&build.join("Makefile")).is_ok() => { - match env::var_os("CARGO_MAKEFLAGS") { - // Only do this on non-windows and non-bsd - // On Windows, we could be invoking make instead of - // mingw32-make which doesn't work with our jobserver - // bsdmake also does not work with our job server - Some(ref s) - if !(cfg!(windows) - || cfg!(target_os = "openbsd") - || cfg!(target_os = "netbsd") - || cfg!(target_os = "freebsd") - || cfg!(target_os = "bitrig") - || cfg!(target_os = "dragonflybsd")) => - { - makeflags = Some(s.clone()) - } - - // This looks like `make`, let's hope it understands `-jN`. - _ => makeflags = Some(OsString::from(format!("-j{}", s))), - } - } - _ => {} - } - } - - // And build! - let target = self.cmake_target.clone().unwrap_or("install".to_string()); - let mut cmd = Command::new(&executable); - for &(ref k, ref v) in c_compiler.env().iter().chain(&self.env) { - cmd.env(k, v); - } - - if let Some(flags) = makeflags { - cmd.env("MAKEFLAGS", flags); - } - - cmd.arg("--build").arg("."); - - if !self.no_build_target { - cmd.arg("--target").arg(target); - } - - cmd.arg("--config") - .arg(&profile) - .arg("--") - .args(&self.build_args) - .current_dir(&build); - - if let Some(flags) = parallel_flags { - cmd.arg(flags); - } - - run(&mut cmd, "cmake"); - - println!("cargo:root={}", dst.display()); - return dst; - } - - fn visual_studio_generator(&self, target: &str) -> String { - use cc::windows_registry::{find_vs_version, VsVers}; - - let base = match find_vs_version() { - Ok(VsVers::Vs16) => "Visual Studio 16 2019", - Ok(VsVers::Vs15) => "Visual Studio 15 2017", - Ok(VsVers::Vs14) => "Visual Studio 14 2015", - Ok(VsVers::Vs12) => "Visual Studio 12 2013", - Ok(_) => panic!( - "Visual studio version detected but this crate \ - doesn't know how to generate cmake files for it, \ - can the `cmake` crate be updated?" - ), - Err(msg) => panic!(msg), - }; - if ["i686", "x86_64", "thumbv7a", "aarch64"] - .iter() - .any(|t| target.contains(t)) - { - base.to_string() - } else { - panic!("unsupported msvc target: {}", target); - } - } - - fn defined(&self, var: &str) -> bool { - self.defines.iter().any(|&(ref a, _)| a == var) - } - - // If a cmake project has previously been built (e.g. CMakeCache.txt already - // exists), then cmake will choke if the source directory for the original - // project being built has changed. Detect this situation through the - // `CMAKE_HOME_DIRECTORY` variable that cmake emits and if it doesn't match - // we blow away the build directory and start from scratch (the recommended - // solution apparently [1]). - // - // [1]: https://cmake.org/pipermail/cmake/2012-August/051545.html - fn maybe_clear(&self, dir: &Path) { - // CMake will apparently store canonicalized paths which normally - // isn't relevant to us but we canonicalize it here to ensure - // we're both checking the same thing. - let path = fs::canonicalize(&self.path).unwrap_or(self.path.clone()); - let mut f = match File::open(dir.join("CMakeCache.txt")) { - Ok(f) => f, - Err(..) => return, - }; - let mut u8contents = Vec::new(); - match f.read_to_end(&mut u8contents) { - Ok(f) => f, - Err(..) => return, - }; - let contents = String::from_utf8_lossy(&u8contents); - drop(f); - for line in contents.lines() { - if line.starts_with("CMAKE_HOME_DIRECTORY") { - let needs_cleanup = match line.split('=').next_back() { - Some(cmake_home) => fs::canonicalize(cmake_home) - .ok() - .map(|cmake_home| cmake_home != path) - .unwrap_or(true), - None => true, - }; - if needs_cleanup { - println!( - "detected home dir change, cleaning out entire build \ - directory" - ); - fs::remove_dir_all(dir).unwrap(); - } - break; - } - } - } -} - -fn run(cmd: &mut Command, program: &str) { - println!("running: {:?}", cmd); - let status = match cmd.status() { - Ok(status) => status, - Err(ref e) if e.kind() == ErrorKind::NotFound => { - fail(&format!( - "failed to execute command: {}\nis `{}` not installed?", - e, program - )); - } - Err(e) => fail(&format!("failed to execute command: {}", e)), - }; - if !status.success() { - fail(&format!( - "command did not execute successfully, got: {}", - status - )); - } -} - -fn find_exe(path: &Path) -> PathBuf { - env::split_paths(&env::var_os("PATH").unwrap_or(OsString::new())) - .map(|p| p.join(path)) - .find(|p| fs::metadata(p).is_ok()) - .unwrap_or(path.to_owned()) -} - -fn getenv_unwrap(v: &str) -> String { - match env::var(v) { - Ok(s) => s, - Err(..) => fail(&format!("environment variable `{}` not defined", v)), - } -} - -fn fail(s: &str) -> ! { - panic!("\n{}\n\nbuild script failed, must exit now", s) -} diff --git a/third_party/cargo/vendor/cocoa-0.19.1/.cargo-checksum.json b/third_party/cargo/vendor/cocoa-0.19.1/.cargo-checksum.json deleted file mode 100644 index 8e9ee70..0000000 --- a/third_party/cargo/vendor/cocoa-0.19.1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.lock":"17a7bea6d9dc55027974371b67cac9b7e88d7a8d82993a66b4dd0fde612fb83c","Cargo.toml":"97c04060532c13f38c492e9623e3f20ae674dfad8ece40ba2d40ac9559cb3c5b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"29542cb34adb016506822ef78bceacf1774dbe8c27818a4d47b7d7b71ed4e1ac","examples/color.rs":"5211a85ab9ec4cbb98f8f677de50bb2f1d300400f50226ebfd714d40b9d32485","examples/fullscreen.rs":"f8719268b6eb1d19078af347e02f9993c9d29633ef2d38dcc4fac26cbd731c2d","examples/hello_world.rs":"7efe2a29de4d4dfc1d8821f469e13b1456f72de478bab55f813d08d4e5aafd5c","examples/tab_view.rs":"e6a3187eeac2f46210994293c2db7756757f4cad07e519902fa994c6d5c1a7d6","src/appkit.rs":"a21c6d612d0ec45dbbb5df45fe96d84b76c5a9982d09bdf74714ce63723da558","src/base.rs":"6c56d1758a9b0a7f8927771fe8b0bb43c6f19e4531bf9accecc786028eaad845","src/foundation.rs":"f0a8c0d2e3aee6bde64f480085025dfa92f903a39d6c15251ba392523aa153a3","src/lib.rs":"ed6164b3e0fe68579218185267d79229a2989c86efce690d7273f779c5239ec3","src/macros.rs":"0de0a8ea9a23f03cad94266a92051c3be8ff3f8f7d7d60f95dafe6c663204d48","src/quartzcore.rs":"cb4f96b4b095e9d623346a42b1e119a5299bf2af73ed81256dd548c688d525e2","tests/foundation.rs":"728eb7dcc9edbfb43dcb6aa1ebcc391658a7d47846d94a71905bcedfce833260"},"package":"f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cocoa-0.19.1/BUILD.bazel b/third_party/cargo/vendor/cocoa-0.19.1/BUILD.bazel deleted file mode 100644 index 2befcc2..0000000 --- a/third_party/cargo/vendor/cocoa-0.19.1/BUILD.bazel +++ /dev/null @@ -1,70 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -# Unsupported target "color" with type "example" omitted - -# Unsupported target "fullscreen" with type "example" omitted - -# Unsupported target "hello_world" with type "example" omitted - -# Unsupported target "tab_view" with type "example" omitted - -rust_library( - name = "cocoa", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "rlib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.19.1", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", - "//third_party/cargo/vendor/block-0.1.6:block", - "//third_party/cargo/vendor/core-foundation-0.6.4:core_foundation", - "//third_party/cargo/vendor/core-graphics-0.17.3:core_graphics", - "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", - "//third_party/cargo/vendor/libc-0.2.71:libc", - "//third_party/cargo/vendor/objc-0.2.7:objc", - ], -) - -# Unsupported target "foundation" with type "test" omitted diff --git a/third_party/cargo/vendor/cocoa-0.19.1/Cargo.lock b/third_party/cargo/vendor/cocoa-0.19.1/Cargo.lock deleted file mode 100644 index d354080..0000000 --- a/third_party/cargo/vendor/cocoa-0.19.1/Cargo.lock +++ /dev/null @@ -1,95 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cocoa" -version = "0.19.1" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core-foundation-sys" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "core-graphics" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.64" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "objc" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c" -"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d" diff --git a/third_party/cargo/vendor/cocoa-0.19.1/Cargo.toml b/third_party/cargo/vendor/cocoa-0.19.1/Cargo.toml deleted file mode 100644 index 26f03e1..0000000 --- a/third_party/cargo/vendor/cocoa-0.19.1/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "cocoa" -version = "0.19.1" -authors = ["The Servo Project Developers"] -description = "Bindings to Cocoa for macOS" -homepage = "https://github.com/servo/core-foundation-rs" -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/core-foundation-rs" - -[lib] -name = "cocoa" -crate-type = ["rlib"] -[dependencies.bitflags] -version = "1.0" - -[dependencies.block] -version = "0.1" - -[dependencies.core-foundation] -version = "0.6" - -[dependencies.core-graphics] -version = "0.17" - -[dependencies.foreign-types] -version = "0.3" - -[dependencies.libc] -version = "0.2" - -[dependencies.objc] -version = "0.2.3" diff --git a/third_party/cargo/vendor/cocoa-0.19.1/src/foundation.rs b/third_party/cargo/vendor/cocoa-0.19.1/src/foundation.rs deleted file mode 100644 index d87c446..0000000 --- a/third_party/cargo/vendor/cocoa-0.19.1/src/foundation.rs +++ /dev/null @@ -1,1318 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_upper_case_globals)] - -use std::ptr; -use std::os::raw::c_void; -use base::{id, BOOL, NO, SEL, nil}; -use block::Block; -use libc; - - -#[cfg(target_pointer_width = "32")] -pub type NSInteger = libc::c_int; -#[cfg(target_pointer_width = "32")] -pub type NSUInteger = libc::c_uint; - -#[cfg(target_pointer_width = "64")] -pub type NSInteger = libc::c_long; -#[cfg(target_pointer_width = "64")] -pub type NSUInteger = libc::c_ulong; - -pub const NSIntegerMax: NSInteger = NSInteger::max_value(); -pub const NSNotFound: NSInteger = NSIntegerMax; - -const UTF8_ENCODING: usize = 4; - -#[cfg(target_os = "macos")] -mod macos { - use std::mem; - use base::id; - use core_graphics::base::CGFloat; - use core_graphics::geometry::CGRect; - use objc; - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct NSPoint { - pub x: CGFloat, - pub y: CGFloat, - } - - impl NSPoint { - #[inline] - pub fn new(x: CGFloat, y: CGFloat) -> NSPoint { - NSPoint { - x: x, - y: y, - } - } - } - - unsafe impl objc::Encode for NSPoint { - fn encode() -> objc::Encoding { - let encoding = format!("{{CGPoint={}{}}}", - CGFloat::encode().as_str(), - CGFloat::encode().as_str()); - unsafe { objc::Encoding::from_str(&encoding) } - } - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct NSSize { - pub width: CGFloat, - pub height: CGFloat, - } - - impl NSSize { - #[inline] - pub fn new(width: CGFloat, height: CGFloat) -> NSSize { - NSSize { - width: width, - height: height, - } - } - } - - unsafe impl objc::Encode for NSSize { - fn encode() -> objc::Encoding { - let encoding = format!("{{CGSize={}{}}}", - CGFloat::encode().as_str(), - CGFloat::encode().as_str()); - unsafe { objc::Encoding::from_str(&encoding) } - } - } - - #[repr(C)] - #[derive(Copy, Clone)] - pub struct NSRect { - pub origin: NSPoint, - pub size: NSSize, - } - - impl NSRect { - #[inline] - pub fn new(origin: NSPoint, size: NSSize) -> NSRect { - NSRect { - origin: origin, - size: size - } - } - - #[inline] - pub fn as_CGRect(&self) -> &CGRect { - unsafe { - mem::transmute::<&NSRect, &CGRect>(self) - } - } - - #[inline] - pub fn inset(&self, x: CGFloat, y: CGFloat) -> NSRect { - unsafe { - NSInsetRect(*self, x, y) - } - } - } - - unsafe impl objc::Encode for NSRect { - fn encode() -> objc::Encoding { - let encoding = format!("{{CGRect={}{}}}", - NSPoint::encode().as_str(), - NSSize::encode().as_str()); - unsafe { objc::Encoding::from_str(&encoding) } - } - } - - // Same as CGRectEdge - #[repr(u32)] - pub enum NSRectEdge { - NSRectMinXEdge, - NSRectMinYEdge, - NSRectMaxXEdge, - NSRectMaxYEdge, - } - - #[link(name = "Foundation", kind = "framework")] - extern { - fn NSInsetRect(rect: NSRect, x: CGFloat, y: CGFloat) -> NSRect; - } - - pub trait NSValue: Sized { - unsafe fn valueWithPoint(_: Self, point: NSPoint) -> id { - msg_send![class!(NSValue), valueWithPoint:point] - } - - unsafe fn valueWithSize(_: Self, size: NSSize) -> id { - msg_send![class!(NSValue), valueWithSize:size] - } - } - - impl NSValue for id { - } -} - -#[cfg(target_os = "macos")] -pub use self::macos::*; - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct NSRange { - pub location: NSUInteger, - pub length: NSUInteger, -} - -impl NSRange { - #[inline] - pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange { - NSRange { - location: location, - length: length - } - } -} - -#[link(name = "Foundation", kind = "framework")] -extern { - pub static NSDefaultRunLoopMode: id; -} - -pub trait NSAutoreleasePool: Sized { - unsafe fn new(_: Self) -> id { - msg_send![class!(NSAutoreleasePool), new] - } - - unsafe fn autorelease(self) -> Self; - unsafe fn drain(self); -} - -impl NSAutoreleasePool for id { - unsafe fn autorelease(self) -> id { - msg_send![self, autorelease] - } - - unsafe fn drain(self) { - msg_send![self, drain] - } -} - -pub trait NSProcessInfo: Sized { - unsafe fn processInfo(_: Self) -> id { - msg_send![class!(NSProcessInfo), processInfo] - } - - unsafe fn processName(self) -> id; -} - -impl NSProcessInfo for id { - unsafe fn processName(self) -> id { - msg_send![self, processName] - } -} - -pub type NSTimeInterval = libc::c_double; - -pub trait NSArray: Sized { - unsafe fn array(_: Self) -> id { - msg_send![class!(NSArray), array] - } - - unsafe fn arrayWithObjects(_: Self, objects: &[id]) -> id { - msg_send![class!(NSArray), arrayWithObjects:objects.as_ptr() - count:objects.len()] - } - - unsafe fn arrayWithObject(_: Self, object: id) -> id { - msg_send![class!(NSArray), arrayWithObject:object] - } - - unsafe fn init(self) -> id; - - unsafe fn count(self) -> NSUInteger; - - unsafe fn arrayByAddingObjectFromArray(self, object: id) -> id; - unsafe fn arrayByAddingObjectsFromArray(self, objects: id) -> id; - unsafe fn objectAtIndex(self, index: NSUInteger) -> id; -} - -impl NSArray for id { - unsafe fn init(self) -> id { - msg_send![self, init] - } - - unsafe fn count(self) -> NSUInteger { - msg_send![self, count] - } - - unsafe fn arrayByAddingObjectFromArray(self, object: id) -> id { - msg_send![self, arrayByAddingObjectFromArray:object] - } - - unsafe fn arrayByAddingObjectsFromArray(self, objects: id) -> id { - msg_send![self, arrayByAddingObjectsFromArray:objects] - } - - unsafe fn objectAtIndex(self, index: NSUInteger) -> id { - msg_send![self, objectAtIndex:index] - } -} - -pub trait NSDictionary: Sized { - unsafe fn dictionary(_: Self) -> id { - msg_send![class!(NSDictionary), dictionary] - } - - unsafe fn dictionaryWithContentsOfFile_(_: Self, path: id) -> id { - msg_send![class!(NSDictionary), dictionaryWithContentsOfFile:path] - } - - unsafe fn dictionaryWithContentsOfURL_(_: Self, aURL: id) -> id { - msg_send![class!(NSDictionary), dictionaryWithContentsOfURL:aURL] - } - - unsafe fn dictionaryWithDictionary_(_: Self, otherDictionary: id) -> id { - msg_send![class!(NSDictionary), dictionaryWithDictionary:otherDictionary] - } - - unsafe fn dictionaryWithObject_forKey_(_: Self, anObject: id, aKey: id) -> id { - msg_send![class!(NSDictionary), dictionaryWithObject:anObject forKey:aKey] - } - - unsafe fn dictionaryWithObjects_forKeys_(_: Self, objects: id, keys: id) -> id { - msg_send![class!(NSDictionary), dictionaryWithObjects:objects forKeys:keys] - } - - unsafe fn dictionaryWithObjects_forKeys_count_(_: Self, objects: *const id, keys: *const id, count: NSUInteger) -> id { - msg_send![class!(NSDictionary), dictionaryWithObjects:objects forKeys:keys count:count] - } - - unsafe fn dictionaryWithObjectsAndKeys_(_: Self, firstObject: id) -> id { - msg_send![class!(NSDictionary), dictionaryWithObjectsAndKeys:firstObject] - } - - unsafe fn init(self) -> id; - unsafe fn initWithContentsOfFile_(self, path: id) -> id; - unsafe fn initWithContentsOfURL_(self, aURL: id) -> id; - unsafe fn initWithDictionary_(self, otherDicitonary: id) -> id; - unsafe fn initWithDictionary_copyItems_(self, otherDicitonary: id, flag: BOOL) -> id; - unsafe fn initWithObjects_forKeys_(self, objects: id, keys: id) -> id; - unsafe fn initWithObjects_forKeys_count_(self, objects: id, keys: id, count: NSUInteger) -> id; - unsafe fn initWithObjectsAndKeys_(self, firstObject: id) -> id; - - unsafe fn sharedKeySetForKeys_(_: Self, keys: id) -> id { - msg_send![class!(NSDictionary), sharedKeySetForKeys:keys] - } - - unsafe fn count(self) -> NSUInteger; - - unsafe fn isEqualToDictionary_(self, otherDictionary: id) -> BOOL; - - unsafe fn allKeys(self) -> id; - unsafe fn allKeysForObject_(self, anObject: id) -> id; - unsafe fn allValues(self) -> id; - unsafe fn objectForKey_(self, aKey: id) -> id; - unsafe fn objectForKeyedSubscript_(self, key: id) -> id; - unsafe fn objectsForKeys_notFoundMarker_(self, keys: id, anObject: id) -> id; - unsafe fn valueForKey_(self, key: id) -> id; - - unsafe fn keyEnumerator(self) -> id; - unsafe fn objectEnumerator(self) -> id; - unsafe fn enumerateKeysAndObjectsUsingBlock_(self, block: *mut Block<(id, id, *mut BOOL), ()>); - unsafe fn enumerateKeysAndObjectsWithOptions_usingBlock_(self, opts: NSEnumerationOptions, - block: *mut Block<(id, id, *mut BOOL), ()>); - - unsafe fn keysSortedByValueUsingSelector_(self, comparator: SEL) -> id; - unsafe fn keysSortedByValueUsingComparator_(self, cmptr: NSComparator) -> id; - unsafe fn keysSortedByValueWithOptions_usingComparator_(self, opts: NSEnumerationOptions, cmptr: NSComparator) -> id; - - unsafe fn keysOfEntriesPassingTest_(self, predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id; - unsafe fn keysOfEntriesWithOptions_PassingTest_(self, opts: NSEnumerationOptions, - predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id; - - unsafe fn writeToFile_atomically_(self, path: id, flag: BOOL) -> BOOL; - unsafe fn writeToURL_atomically_(self, aURL: id, flag: BOOL) -> BOOL; - - unsafe fn fileCreationDate(self) -> id; - unsafe fn fileExtensionHidden(self) -> BOOL; - unsafe fn fileGroupOwnerAccountID(self) -> id; - unsafe fn fileGroupOwnerAccountName(self) -> id; - unsafe fn fileIsAppendOnly(self) -> BOOL; - unsafe fn fileIsImmutable(self) -> BOOL; - unsafe fn fileModificationDate(self) -> id; - unsafe fn fileOwnerAccountID(self) -> id; - unsafe fn fileOwnerAccountName(self) -> id; - unsafe fn filePosixPermissions(self) -> NSUInteger; - unsafe fn fileSize(self) -> libc::c_ulonglong; - unsafe fn fileSystemFileNumber(self) -> NSUInteger; - unsafe fn fileSystemNumber(self) -> NSInteger; - unsafe fn fileType(self) -> id; - - unsafe fn description(self) -> id; - unsafe fn descriptionInStringsFileFormat(self) -> id; - unsafe fn descriptionWithLocale_(self, locale: id) -> id; - unsafe fn descriptionWithLocale_indent_(self, locale: id, indent: NSUInteger) -> id; -} - -impl NSDictionary for id { - unsafe fn init(self) -> id { - msg_send![self, init] - } - - unsafe fn initWithContentsOfFile_(self, path: id) -> id { - msg_send![self, initWithContentsOfFile:path] - } - - unsafe fn initWithContentsOfURL_(self, aURL: id) -> id { - msg_send![self, initWithContentsOfURL:aURL] - } - - unsafe fn initWithDictionary_(self, otherDictionary: id) -> id { - msg_send![self, initWithDictionary:otherDictionary] - } - - unsafe fn initWithDictionary_copyItems_(self, otherDictionary: id, flag: BOOL) -> id { - msg_send![self, initWithDictionary:otherDictionary copyItems:flag] - } - - unsafe fn initWithObjects_forKeys_(self, objects: id, keys: id) -> id { - msg_send![self, initWithObjects:objects forKeys:keys] - } - - unsafe fn initWithObjects_forKeys_count_(self, objects: id, keys: id, count: NSUInteger) -> id { - msg_send![self, initWithObjects:objects forKeys:keys count:count] - } - - unsafe fn initWithObjectsAndKeys_(self, firstObject: id) -> id { - msg_send![self, initWithObjectsAndKeys:firstObject] - } - - unsafe fn count(self) -> NSUInteger { - msg_send![self, count] - } - - unsafe fn isEqualToDictionary_(self, otherDictionary: id) -> BOOL { - msg_send![self, isEqualToDictionary:otherDictionary] - } - - unsafe fn allKeys(self) -> id { - msg_send![self, allKeys] - } - - unsafe fn allKeysForObject_(self, anObject: id) -> id { - msg_send![self, allKeysForObject:anObject] - } - - unsafe fn allValues(self) -> id { - msg_send![self, allValues] - } - - unsafe fn objectForKey_(self, aKey: id) -> id { - msg_send![self, objectForKey:aKey] - } - - unsafe fn objectForKeyedSubscript_(self, key: id) -> id { - msg_send![self, objectForKeyedSubscript:key] - } - - unsafe fn objectsForKeys_notFoundMarker_(self, keys: id, anObject: id) -> id { - msg_send![self, objectsForKeys:keys notFoundMarker:anObject] - } - - unsafe fn valueForKey_(self, key: id) -> id { - msg_send![self, valueForKey:key] - } - - unsafe fn keyEnumerator(self) -> id { - msg_send![self, keyEnumerator] - } - - unsafe fn objectEnumerator(self) -> id { - msg_send![self, objectEnumerator] - } - - unsafe fn enumerateKeysAndObjectsUsingBlock_(self, block: *mut Block<(id, id, *mut BOOL), ()>) { - msg_send![self, enumerateKeysAndObjectsUsingBlock:block] - } - - unsafe fn enumerateKeysAndObjectsWithOptions_usingBlock_(self, opts: NSEnumerationOptions, - block: *mut Block<(id, id, *mut BOOL), ()>) { - msg_send![self, enumerateKeysAndObjectsWithOptions:opts usingBlock:block] - } - - unsafe fn keysSortedByValueUsingSelector_(self, comparator: SEL) -> id { - msg_send![self, keysSortedByValueUsingSelector:comparator] - } - - unsafe fn keysSortedByValueUsingComparator_(self, cmptr: NSComparator) -> id { - msg_send![self, keysSortedByValueUsingComparator:cmptr] - } - - unsafe fn keysSortedByValueWithOptions_usingComparator_(self, opts: NSEnumerationOptions, cmptr: NSComparator) -> id { - let rv: id = msg_send![self, keysSortedByValueWithOptions:opts usingComparator:cmptr]; - rv - } - - unsafe fn keysOfEntriesPassingTest_(self, predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id { - msg_send![self, keysOfEntriesPassingTest:predicate] - } - - unsafe fn keysOfEntriesWithOptions_PassingTest_(self, opts: NSEnumerationOptions, - predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id { - msg_send![self, keysOfEntriesWithOptions:opts PassingTest:predicate] - } - - unsafe fn writeToFile_atomically_(self, path: id, flag: BOOL) -> BOOL { - msg_send![self, writeToFile:path atomically:flag] - } - - unsafe fn writeToURL_atomically_(self, aURL: id, flag: BOOL) -> BOOL { - msg_send![self, writeToURL:aURL atomically:flag] - } - - unsafe fn fileCreationDate(self) -> id { - msg_send![self, fileCreationDate] - } - - unsafe fn fileExtensionHidden(self) -> BOOL { - msg_send![self, fileExtensionHidden] - } - - unsafe fn fileGroupOwnerAccountID(self) -> id { - msg_send![self, fileGroupOwnerAccountID] - } - - unsafe fn fileGroupOwnerAccountName(self) -> id { - msg_send![self, fileGroupOwnerAccountName] - } - - unsafe fn fileIsAppendOnly(self) -> BOOL { - msg_send![self, fileIsAppendOnly] - } - - unsafe fn fileIsImmutable(self) -> BOOL { - msg_send![self, fileIsImmutable] - } - - unsafe fn fileModificationDate(self) -> id { - msg_send![self, fileModificationDate] - } - - unsafe fn fileOwnerAccountID(self) -> id { - msg_send![self, fileOwnerAccountID] - } - - unsafe fn fileOwnerAccountName(self) -> id { - msg_send![self, fileOwnerAccountName] - } - - unsafe fn filePosixPermissions(self) -> NSUInteger { - msg_send![self, filePosixPermissions] - } - - unsafe fn fileSize(self) -> libc::c_ulonglong { - msg_send![self, fileSize] - } - - unsafe fn fileSystemFileNumber(self) -> NSUInteger { - msg_send![self, fileSystemFileNumber] - } - - unsafe fn fileSystemNumber(self) -> NSInteger { - msg_send![self, fileSystemNumber] - } - - unsafe fn fileType(self) -> id { - msg_send![self, fileType] - } - - unsafe fn description(self) -> id { - msg_send![self, description] - } - - unsafe fn descriptionInStringsFileFormat(self) -> id { - msg_send![self, descriptionInStringsFileFormat] - } - - unsafe fn descriptionWithLocale_(self, locale: id) -> id { - msg_send![self, descriptionWithLocale:locale] - } - - unsafe fn descriptionWithLocale_indent_(self, locale: id, indent: NSUInteger) -> id { - msg_send![self, descriptionWithLocale:locale indent:indent] - } -} - -bitflags! { - pub struct NSEnumerationOptions: libc::c_ulonglong { - const NSEnumerationConcurrent = 1 << 0; - const NSEnumerationReverse = 1 << 1; - } -} - -pub type NSComparator = *mut Block<(id, id), NSComparisonResult>; - -#[repr(isize)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum NSComparisonResult { - NSOrderedAscending = -1, - NSOrderedSame = 0, - NSOrderedDescending = 1 -} - -pub trait NSString: Sized { - unsafe fn alloc(_: Self) -> id { - msg_send![class!(NSString), alloc] - } - - unsafe fn stringByAppendingString_(self, other: id) -> id; - unsafe fn init_str(self, string: &str) -> Self; - unsafe fn UTF8String(self) -> *const libc::c_char; - unsafe fn len(self) -> usize; - unsafe fn isEqualToString(self, &str) -> bool; - unsafe fn substringWithRange(self, range: NSRange) -> id; -} - -impl NSString for id { - unsafe fn isEqualToString(self, other: &str) -> bool { - let other = NSString::alloc(nil).init_str(other); - let rv: BOOL = msg_send![self, isEqualToString:other]; - rv != NO - } - - unsafe fn stringByAppendingString_(self, other: id) -> id { - msg_send![self, stringByAppendingString:other] - } - - unsafe fn init_str(self, string: &str) -> id { - return msg_send![self, - initWithBytes:string.as_ptr() - length:string.len() - encoding:UTF8_ENCODING as id]; - } - - unsafe fn len(self) -> usize { - msg_send![self, lengthOfBytesUsingEncoding:UTF8_ENCODING] - } - - unsafe fn UTF8String(self) -> *const libc::c_char { - msg_send![self, UTF8String] - } - - unsafe fn substringWithRange(self, range: NSRange) -> id { - msg_send![self, substringWithRange:range] - } -} - -pub trait NSDate: Sized { - unsafe fn distantPast(_: Self) -> id { - msg_send![class!(NSDate), distantPast] - } - - unsafe fn distantFuture(_: Self) -> id { - msg_send![class!(NSDate), distantFuture] - } -} - -impl NSDate for id { - -} - -#[repr(C)] -struct NSFastEnumerationState { - pub state: libc::c_ulong, - pub items_ptr: *mut id, - pub mutations_ptr: *mut libc::c_ulong, - pub extra: [libc::c_ulong; 5] -} - -const NS_FAST_ENUM_BUF_SIZE: usize = 16; - -pub struct NSFastIterator { - state: NSFastEnumerationState, - buffer: [id; NS_FAST_ENUM_BUF_SIZE], - mut_val: Option, - len: usize, - idx: usize, - object: id -} - -impl Iterator for NSFastIterator { - type Item = id; - - fn next(&mut self) -> Option { - if self.idx >= self.len { - self.len = unsafe { - msg_send![self.object, countByEnumeratingWithState:&mut self.state objects:self.buffer.as_mut_ptr() count:NS_FAST_ENUM_BUF_SIZE] - }; - self.idx = 0; - } - - let new_mut = unsafe { - *self.state.mutations_ptr - }; - - if let Some(old_mut) = self.mut_val { - assert!(old_mut == new_mut, "The collection was mutated while being enumerated"); - } - - if self.idx < self.len { - let object = unsafe { - *self.state.items_ptr.offset(self.idx as isize) - }; - self.mut_val = Some(new_mut); - self.idx += 1; - Some(object) - } else { - None - } - } -} - -pub trait NSFastEnumeration: Sized { - unsafe fn iter(self) -> NSFastIterator; -} - -impl NSFastEnumeration for id { - unsafe fn iter(self) -> NSFastIterator { - NSFastIterator { - state: NSFastEnumerationState { - state: 0, - items_ptr: ptr::null_mut(), - mutations_ptr: ptr::null_mut(), - extra: [0; 5] - }, - buffer: [nil; NS_FAST_ENUM_BUF_SIZE], - mut_val: None, - len: 0, - idx: 0, - object: self - } - } -} - -pub trait NSRunLoop: Sized { - unsafe fn currentRunLoop() -> Self; - - unsafe fn performSelector_target_argument_order_modes_(self, - aSelector: SEL, - target: id, - anArgument: id, - order: NSUInteger, - modes: id); -} - -impl NSRunLoop for id { - unsafe fn currentRunLoop() -> id { - msg_send![class!(NSRunLoop), currentRunLoop] - } - - unsafe fn performSelector_target_argument_order_modes_(self, - aSelector: SEL, - target: id, - anArgument: id, - order: NSUInteger, - modes: id) { - msg_send![self, performSelector:aSelector - target:target - argument:anArgument - order:order - modes:modes] - } -} - -bitflags! { - pub struct NSURLBookmarkCreationOptions: NSUInteger { - const NSURLBookmarkCreationPreferFileIDResolution = 1 << 8; - const NSURLBookmarkCreationMinimalBookmark = 1 << 9; - const NSURLBookmarkCreationSuitableForBookmarkFile = 1 << 10; - const NSURLBookmarkCreationWithSecurityScope = 1 << 11; - const NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess = 1 << 12; - } -} - -pub type NSURLBookmarkFileCreationOptions = NSURLBookmarkCreationOptions; - -bitflags! { - pub struct NSURLBookmarkResolutionOptions: NSUInteger { - const NSURLBookmarkResolutionWithoutUI = 1 << 8; - const NSURLBookmarkResolutionWithoutMounting = 1 << 9; - const NSURLBookmarkResolutionWithSecurityScope = 1 << 10; - } -} - - -pub trait NSURL: Sized { - unsafe fn alloc(_: Self) -> id; - - unsafe fn URLWithString_(_:Self, string: id) -> id; - unsafe fn initWithString_(self, string: id) -> id; - unsafe fn URLWithString_relativeToURL_(_:Self, string: id, url: id) -> id; - unsafe fn initWithString_relativeToURL_(self, string: id, url: id) -> id; - unsafe fn fileURLWithPath_isDirectory_(_:Self, path: id, is_dir: BOOL) -> id; - unsafe fn initFileURLWithPath_isDirectory_(self, path: id, is_dir: BOOL) -> id; - unsafe fn fileURLWithPath_relativeToURL_(_:Self, path: id, url: id) -> id; - unsafe fn initFileURLWithPath_relativeToURL_(self, path: id, url: id) -> id; - unsafe fn fileURLWithPath_isDirectory_relativeToURL_(_:Self, path: id, is_dir: BOOL, url: id) -> id; - unsafe fn initFileURLWithPath_isDirectory_relativeToURL_(self, path: id, is_dir: BOOL, url: id) -> id; - unsafe fn fileURLWithPath_(_:Self, path: id) -> id; - unsafe fn initFileURLWithPath_(self, path: id) -> id; - unsafe fn fileURLWithPathComponents_(_:Self, path_components: id /* (NSArray*) */) -> id; - unsafe fn URLByResolvingAliasFileAtURL_options_error_(_:Self, url: id, options: NSURLBookmarkResolutionOptions, error: *mut id /* (NSError _Nullable) */) -> id; - unsafe fn URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(_:Self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id; - unsafe fn initByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id; - // unsafe fn fileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ - // unsafe fn getFileSystemRepresentation_maxLength_ - // unsafe fn initFileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ - unsafe fn absoluteURLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id; - unsafe fn initAbsoluteURLWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id; - unsafe fn URLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id; - unsafe fn initWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id; - unsafe fn dataRepresentation(self) -> id /* (NSData) */; - - unsafe fn isEqual_(self, id: id) -> BOOL; - - unsafe fn checkResourceIsReachableAndReturnError_(self, error: id /* (NSError _Nullable) */) -> BOOL; - unsafe fn isFileReferenceURL(self) -> BOOL; - unsafe fn isFileURL(self) -> BOOL; - - unsafe fn absoluteString(self) -> id /* (NSString) */; - unsafe fn absoluteURL(self) -> id /* (NSURL) */; - unsafe fn baseURL(self) -> id /* (NSURL) */; - // unsafe fn fileSystemRepresentation - unsafe fn fragment(self) -> id /* (NSString) */; - unsafe fn host(self) -> id /* (NSString) */; - unsafe fn lastPathComponent(self) -> id /* (NSString) */; - unsafe fn parameterString(self) -> id /* (NSString) */; - unsafe fn password(self) -> id /* (NSString) */; - unsafe fn path(self) -> id /* (NSString) */; - unsafe fn pathComponents(self) -> id /* (NSArray) */; - unsafe fn pathExtension(self) -> id /* (NSString) */; - unsafe fn port(self) -> id /* (NSNumber) */; - unsafe fn query(self) -> id /* (NSString) */; - unsafe fn relativePath(self) -> id /* (NSString) */; - unsafe fn relativeString(self) -> id /* (NSString) */; - unsafe fn resourceSpecifier(self) -> id /* (NSString) */; - unsafe fn scheme(self) -> id /* (NSString) */; - unsafe fn standardizedURL(self) -> id /* (NSURL) */; - unsafe fn user(self) -> id /* (NSString) */; - - // unsafe fn resourceValuesForKeys_error_ - // unsafe fn getResourceValue_forKey_error_ - // unsafe fn setResourceValue_forKey_error_ - // unsafe fn setResourceValues_error_ - // unsafe fn removeAllCachedResourceValues - // unsafe fn removeCachedResourceValueForKey_ - // unsafe fn setTemporaryResourceValue_forKey_ - unsafe fn NSURLResourceKey(self) -> id /* (NSString) */; - - unsafe fn filePathURL(self) -> id; - unsafe fn fileReferenceURL(self) -> id; - unsafe fn URLByAppendingPathComponent_(self, path_component: id /* (NSString) */) -> id; - unsafe fn URLByAppendingPathComponent_isDirectory_(self, path_component: id /* (NSString) */, is_dir: BOOL) -> id; - unsafe fn URLByAppendingPathExtension_(self, extension: id /* (NSString) */) -> id; - unsafe fn URLByDeletingLastPathComponent(self) -> id; - unsafe fn URLByDeletingPathExtension(self) -> id; - unsafe fn URLByResolvingSymlinksInPath(self) -> id; - unsafe fn URLByStandardizingPath(self) -> id; - unsafe fn hasDirectoryPath(self) -> BOOL; - - unsafe fn bookmarkDataWithContentsOfURL_error_(_:Self, url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */; - unsafe fn bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(self, options: NSURLBookmarkCreationOptions, resource_value_for_keys: id /* (NSArray) */, relative_to_url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */; - // unsafe fn resourceValuesForKeys_fromBookmarkData_ - unsafe fn writeBookmarkData_toURL_options_error_(_:Self, data: id /* (NSData) */, to_url: id, options: NSURLBookmarkFileCreationOptions, error: id /* (NSError _Nullable) */) -> id; - unsafe fn startAccessingSecurityScopedResource(self) -> BOOL; - unsafe fn stopAccessingSecurityScopedResource(self); - unsafe fn NSURLBookmarkFileCreationOptions(self) -> NSURLBookmarkFileCreationOptions; - unsafe fn NSURLBookmarkCreationOptions(self) -> NSURLBookmarkCreationOptions; - unsafe fn NSURLBookmarkResolutionOptions(self) -> NSURLBookmarkResolutionOptions; - - // unsafe fn checkPromisedItemIsReachableAndReturnError_ - // unsafe fn getPromisedItemResourceValue_forKey_error_ - // unsafe fn promisedItemResourceValuesForKeys_error_ - - // unsafe fn URLFromPasteboard_ - // unsafe fn writeToPasteboard_ -} - -impl NSURL for id { - unsafe fn alloc(_: Self) -> id { - msg_send![class!(NSURL), alloc] - } - - unsafe fn URLWithString_(_:Self, string: id) -> id { - msg_send![class!(NSURL), URLWithString:string] - } - unsafe fn initWithString_(self, string: id) -> id { - msg_send![self, initWithString:string] - } - unsafe fn URLWithString_relativeToURL_(_:Self, string: id, url: id) -> id { - msg_send![class!(NSURL), URLWithString: string relativeToURL:url] - } - unsafe fn initWithString_relativeToURL_(self, string: id, url: id) -> id { - msg_send![self, initWithString:string relativeToURL:url] - } - unsafe fn fileURLWithPath_isDirectory_(_:Self, path: id, is_dir: BOOL) -> id { - msg_send![class!(NSURL), fileURLWithPath:path isDirectory:is_dir] - } - unsafe fn initFileURLWithPath_isDirectory_(self, path: id, is_dir: BOOL) -> id { - msg_send![self, initFileURLWithPath:path isDirectory:is_dir] - } - unsafe fn fileURLWithPath_relativeToURL_(_:Self, path: id, url: id) -> id { - msg_send![class!(NSURL), fileURLWithPath:path relativeToURL:url] - } - unsafe fn initFileURLWithPath_relativeToURL_(self, path: id, url: id) -> id { - msg_send![self, initFileURLWithPath:path relativeToURL:url] - } - unsafe fn fileURLWithPath_isDirectory_relativeToURL_(_:Self, path: id, is_dir: BOOL, url: id) -> id { - msg_send![class!(NSURL), fileURLWithPath:path isDirectory:is_dir relativeToURL:url] - } - unsafe fn initFileURLWithPath_isDirectory_relativeToURL_(self, path: id, is_dir: BOOL, url: id) -> id { - msg_send![self, initFileURLWithPath:path isDirectory:is_dir relativeToURL:url] - } - unsafe fn fileURLWithPath_(_:Self, path: id) -> id { - msg_send![class!(NSURL), fileURLWithPath:path] - } - unsafe fn initFileURLWithPath_(self, path: id) -> id { - msg_send![self, initFileURLWithPath:path] - } - unsafe fn fileURLWithPathComponents_(_:Self, path_components: id /* (NSArray*) */) -> id { - msg_send![class!(NSURL), fileURLWithPathComponents:path_components] - } - unsafe fn URLByResolvingAliasFileAtURL_options_error_(_:Self, url: id, options: NSURLBookmarkResolutionOptions, error: *mut id /* (NSError _Nullable) */) -> id { - msg_send![class!(NSURL), URLByResolvingAliasFileAtURL:url options:options error:error] - } - unsafe fn URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(_:Self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id { - msg_send![class!(NSURL), URLByResolvingBookmarkData:data options:options relativeToURL:relative_to_url bookmarkDataIsStale:is_stale error:error] - } - unsafe fn initByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id { - msg_send![self, initByResolvingBookmarkData:data options:options relativeToURL:relative_to_url bookmarkDataIsStale:is_stale error:error] - } - // unsafe fn fileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ - // unsafe fn getFileSystemRepresentation_maxLength_ - // unsafe fn initFileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ - unsafe fn absoluteURLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id { - msg_send![class!(NSURL), absoluteURLWithDataRepresentation:data relativeToURL:url] - } - unsafe fn initAbsoluteURLWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id { - msg_send![self, initAbsoluteURLWithDataRepresentation:data relativeToURL:url] - } - unsafe fn URLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id { - msg_send![class!(NSURL), URLWithDataRepresentation:data relativeToURL:url] - } - unsafe fn initWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id { - msg_send![self, initWithDataRepresentation:data relativeToURL:url] - } - unsafe fn dataRepresentation(self) -> id /* (NSData) */ { - msg_send![self, dataRepresentation] - } - - unsafe fn isEqual_(self, id: id) -> BOOL { - msg_send![self, isEqual:id] - } - - unsafe fn checkResourceIsReachableAndReturnError_(self, error: id /* (NSError _Nullable) */) -> BOOL { - msg_send![self, checkResourceIsReachableAndReturnError:error] - } - unsafe fn isFileReferenceURL(self) -> BOOL { - msg_send![self, isFileReferenceURL] - } - unsafe fn isFileURL(self) -> BOOL { - msg_send![self, isFileURL] - } - - unsafe fn absoluteString(self) -> id /* (NSString) */ { - msg_send![self, absoluteString] - } - unsafe fn absoluteURL(self) -> id /* (NSURL) */ { - msg_send![self, absoluteURL] - } - unsafe fn baseURL(self) -> id /* (NSURL) */ { - msg_send![self, baseURL] - } - // unsafe fn fileSystemRepresentation - unsafe fn fragment(self) -> id /* (NSString) */ { - msg_send![self, fragment] - } - unsafe fn host(self) -> id /* (NSString) */ { - msg_send![self, host] - } - unsafe fn lastPathComponent(self) -> id /* (NSString) */ { - msg_send![self, lastPathComponent] - } - unsafe fn parameterString(self) -> id /* (NSString) */ { - msg_send![self, parameterString] - } - unsafe fn password(self) -> id /* (NSString) */ { - msg_send![self, password] - } - unsafe fn path(self) -> id /* (NSString) */ { - msg_send![self, path] - } - unsafe fn pathComponents(self) -> id /* (NSArray) */ { - msg_send![self, pathComponents] - } - unsafe fn pathExtension(self) -> id /* (NSString) */ { - msg_send![self, pathExtension] - } - unsafe fn port(self) -> id /* (NSNumber) */ { - msg_send![self, port] - } - unsafe fn query(self) -> id /* (NSString) */ { - msg_send![self, query] - } - unsafe fn relativePath(self) -> id /* (NSString) */ { - msg_send![self, relativePath] - } - unsafe fn relativeString(self) -> id /* (NSString) */ { - msg_send![self, relativeString] - } - unsafe fn resourceSpecifier(self) -> id /* (NSString) */ { - msg_send![self, resourceSpecifier] - } - unsafe fn scheme(self) -> id /* (NSString) */ { - msg_send![self, scheme] - } - unsafe fn standardizedURL(self) -> id /* (NSURL) */ { - msg_send![self, standardizedURL] - } - unsafe fn user(self) -> id /* (NSString) */ { - msg_send![self, user] - } - - // unsafe fn resourceValuesForKeys_error_ - // unsafe fn getResourceValue_forKey_error_ - // unsafe fn setResourceValue_forKey_error_ - // unsafe fn setResourceValues_error_ - // unsafe fn removeAllCachedResourceValues - // unsafe fn removeCachedResourceValueForKey_ - // unsafe fn setTemporaryResourceValue_forKey_ - unsafe fn NSURLResourceKey(self) -> id /* (NSString) */ { - msg_send![self, NSURLResourceKey] - } - - unsafe fn filePathURL(self) -> id { - msg_send![self, filePathURL] - } - unsafe fn fileReferenceURL(self) -> id { - msg_send![self, fileReferenceURL] - } - unsafe fn URLByAppendingPathComponent_(self, path_component: id /* (NSString) */) -> id { - msg_send![self, URLByAppendingPathComponent:path_component] - } - unsafe fn URLByAppendingPathComponent_isDirectory_(self, path_component: id /* (NSString) */, is_dir: BOOL) -> id { - msg_send![self, URLByAppendingPathComponent:path_component isDirectory:is_dir] - } - unsafe fn URLByAppendingPathExtension_(self, extension: id /* (NSString) */) -> id { - msg_send![self, URLByAppendingPathExtension:extension] - } - unsafe fn URLByDeletingLastPathComponent(self) -> id { - msg_send![self, URLByDeletingLastPathComponent] - } - unsafe fn URLByDeletingPathExtension(self) -> id { - msg_send![self, URLByDeletingPathExtension] - } - unsafe fn URLByResolvingSymlinksInPath(self) -> id { - msg_send![self, URLByResolvingSymlinksInPath] - } - unsafe fn URLByStandardizingPath(self) -> id { - msg_send![self, URLByStandardizingPath] - } - unsafe fn hasDirectoryPath(self) -> BOOL { - msg_send![self, hasDirectoryPath] - } - - unsafe fn bookmarkDataWithContentsOfURL_error_(_:Self, url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */ { - msg_send![class!(NSURL), bookmarkDataWithContentsOfURL:url error:error] - } - unsafe fn bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(self, options: NSURLBookmarkCreationOptions, resource_value_for_keys: id /* (NSArray) */, relative_to_url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */ { - msg_send![self, bookmarkDataWithOptions:options includingResourceValuesForKeys:resource_value_for_keys relativeToURL:relative_to_url error:error] - } - // unsafe fn resourceValuesForKeys_fromBookmarkData_ - unsafe fn writeBookmarkData_toURL_options_error_(_:Self, data: id /* (NSData) */, to_url: id, options: NSURLBookmarkFileCreationOptions, error: id /* (NSError _Nullable) */) -> id { - msg_send![class!(NSURL), writeBookmarkData:data toURL:to_url options:options error:error] - } - unsafe fn startAccessingSecurityScopedResource(self) -> BOOL { - msg_send![self, startAccessingSecurityScopedResource] - } - unsafe fn stopAccessingSecurityScopedResource(self) { - msg_send![self, stopAccessingSecurityScopedResource] - } - unsafe fn NSURLBookmarkFileCreationOptions(self) -> NSURLBookmarkFileCreationOptions { - msg_send![self, NSURLBookmarkFileCreationOptions] - } - unsafe fn NSURLBookmarkCreationOptions(self) -> NSURLBookmarkCreationOptions { - msg_send![self, NSURLBookmarkCreationOptions] - } - unsafe fn NSURLBookmarkResolutionOptions(self) -> NSURLBookmarkResolutionOptions { - msg_send![self, NSURLBookmarkResolutionOptions] - } - - // unsafe fn checkPromisedItemIsReachableAndReturnError_ - // unsafe fn getPromisedItemResourceValue_forKey_error_ - // unsafe fn promisedItemResourceValuesForKeys_error_ - - // unsafe fn URLFromPasteboard_ - // unsafe fn writeToPasteboard_ -} - -pub trait NSBundle: Sized { - unsafe fn mainBundle() -> Self; - - unsafe fn loadNibNamed_owner_topLevelObjects_(self, - name: id /* NSString */, - owner: id, - topLevelObjects: *mut id /* NSArray */) -> BOOL; -} - -impl NSBundle for id { - unsafe fn mainBundle() -> id { - msg_send![class!(NSBundle), mainBundle] - } - - unsafe fn loadNibNamed_owner_topLevelObjects_(self, - name: id /* NSString */, - owner: id, - topLevelObjects: *mut id /* NSArray* */) -> BOOL { - msg_send![self, loadNibNamed:name - owner:owner - topLevelObjects:topLevelObjects] - } -} - -pub trait NSData: Sized { - unsafe fn data(_: Self) -> id { - msg_send![class!(NSData), data] - } - - unsafe fn dataWithBytes_length_(_: Self, bytes: *const c_void, length: NSUInteger) -> id { - msg_send![class!(NSData), dataWithBytes:bytes length:length] - } - - unsafe fn dataWithBytesNoCopy_length_(_: Self, bytes: *const c_void, length: NSUInteger) -> id { - msg_send![class!(NSData), dataWithBytesNoCopy:bytes length:length] - } - - unsafe fn dataWithBytesNoCopy_length_freeWhenDone_(_: Self, bytes: *const c_void, - length: NSUInteger, freeWhenDone: BOOL) -> id { - msg_send![class!(NSData), dataWithBytesNoCopy:bytes length:length freeWhenDone:freeWhenDone] - } - - unsafe fn dataWithContentsOfFile_(_: Self, path: id) -> id { - msg_send![class!(NSData), dataWithContentsOfFile:path] - } - - unsafe fn dataWithContentsOfFile_options_error_(_: Self, path: id, mask: NSDataReadingOptions, - errorPtr: *mut id) -> id { - msg_send![class!(NSData), dataWithContentsOfFile:path options:mask error:errorPtr] - } - - unsafe fn dataWithContentsOfURL_(_: Self, aURL: id) -> id { - msg_send![class!(NSData), dataWithContentsOfURL:aURL] - } - - unsafe fn dataWithContentsOfURL_options_error_(_: Self, aURL: id, mask: NSDataReadingOptions, - errorPtr: *mut id) -> id { - msg_send![class!(NSData), dataWithContentsOfURL:aURL options:mask error:errorPtr] - } - - unsafe fn dataWithData_(_: Self, aData: id) -> id { - msg_send![class!(NSData), dataWithData:aData] - } - - unsafe fn initWithBase64EncodedData_options_(self, base64Data: id, options: NSDataBase64DecodingOptions) - -> id; - unsafe fn initWithBase64EncodedString_options_(self, base64String: id, options: NSDataBase64DecodingOptions) - -> id; - unsafe fn initWithBytes_length_(self, bytes: *const c_void, length: NSUInteger) -> id; - unsafe fn initWithBytesNoCopy_length_(self, bytes: *const c_void, length: NSUInteger) -> id; - unsafe fn initWithBytesNoCopy_length_deallocator_(self, bytes: *const c_void, length: NSUInteger, - deallocator: *mut Block<(*const c_void, NSUInteger), ()>) - -> id; - unsafe fn initWithBytesNoCopy_length_freeWhenDone_(self, bytes: *const c_void, - length: NSUInteger, freeWhenDone: BOOL) -> id; - unsafe fn initWithContentsOfFile_(self, path: id) -> id; - unsafe fn initWithContentsOfFile_options_error(self, path: id, mask: NSDataReadingOptions, errorPtr: *mut id) - -> id; - unsafe fn initWithContentsOfURL_(self, aURL: id) -> id; - unsafe fn initWithContentsOfURL_options_error_(self, aURL: id, mask: NSDataReadingOptions, errorPtr: *mut id) - -> id; - unsafe fn initWithData_(self, data: id) -> id; - - unsafe fn bytes(self) -> *const c_void; - unsafe fn description(self) -> id; - unsafe fn enumerateByteRangesUsingBlock_(self, block: *mut Block<(*const c_void, NSRange, *mut BOOL), ()>); - unsafe fn getBytes_length_(self, buffer: *mut c_void, length: NSUInteger); - unsafe fn getBytes_range_(self, buffer: *mut c_void, range: NSRange); - unsafe fn subdataWithRange_(self, range: NSRange) -> id; - unsafe fn rangeOfData_options_range_(self, dataToFind: id, options: NSDataSearchOptions, searchRange: NSRange) - -> NSRange; - - unsafe fn base64EncodedDataWithOptions_(self, options: NSDataBase64EncodingOptions) -> id; - unsafe fn base64EncodedStringWithOptions_(self, options: NSDataBase64EncodingOptions) -> id; - - unsafe fn isEqualToData_(self, otherData: id) -> id; - unsafe fn length(self) -> NSUInteger; - - unsafe fn writeToFile_atomically_(self, path: id, atomically: BOOL) -> BOOL; - unsafe fn writeToFile_options_error_(self, path: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL; - unsafe fn writeToURL_atomically_(self, aURL: id, atomically: BOOL) -> BOOL; - unsafe fn writeToURL_options_error_(self, aURL: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL; -} - -impl NSData for id { - unsafe fn initWithBase64EncodedData_options_(self, base64Data: id, options: NSDataBase64DecodingOptions) - -> id { - msg_send![self, initWithBase64EncodedData:base64Data options:options] - } - - unsafe fn initWithBase64EncodedString_options_(self, base64String: id, options: NSDataBase64DecodingOptions) - -> id { - msg_send![self, initWithBase64EncodedString:base64String options:options] - } - - unsafe fn initWithBytes_length_(self, bytes: *const c_void, length: NSUInteger) -> id { - msg_send![self,initWithBytes:bytes length:length] - } - - unsafe fn initWithBytesNoCopy_length_(self, bytes: *const c_void, length: NSUInteger) -> id { - msg_send![self, initWithBytesNoCopy:bytes length:length] - } - - unsafe fn initWithBytesNoCopy_length_deallocator_(self, bytes: *const c_void, length: NSUInteger, - deallocator: *mut Block<(*const c_void, NSUInteger), ()>) - -> id { - msg_send![self, initWithBytesNoCopy:bytes length:length deallocator:deallocator] - } - - unsafe fn initWithBytesNoCopy_length_freeWhenDone_(self, bytes: *const c_void, - length: NSUInteger, freeWhenDone: BOOL) -> id { - msg_send![self, initWithBytesNoCopy:bytes length:length freeWhenDone:freeWhenDone] - } - - unsafe fn initWithContentsOfFile_(self, path: id) -> id { - msg_send![self, initWithContentsOfFile:path] - } - - unsafe fn initWithContentsOfFile_options_error(self, path: id, mask: NSDataReadingOptions, errorPtr: *mut id) - -> id { - msg_send![self, initWithContentsOfFile:path options:mask error:errorPtr] - } - - unsafe fn initWithContentsOfURL_(self, aURL: id) -> id { - msg_send![self, initWithContentsOfURL:aURL] - } - - unsafe fn initWithContentsOfURL_options_error_(self, aURL: id, mask: NSDataReadingOptions, errorPtr: *mut id) - -> id { - msg_send![self, initWithContentsOfURL:aURL options:mask error:errorPtr] - } - - unsafe fn initWithData_(self, data: id) -> id { - msg_send![self, initWithData:data] - } - - unsafe fn bytes(self) -> *const c_void { - msg_send![self, bytes] - } - - unsafe fn description(self) -> id { - msg_send![self, description] - } - - unsafe fn enumerateByteRangesUsingBlock_(self, block: *mut Block<(*const c_void, NSRange, *mut BOOL), ()>) { - msg_send![self, enumerateByteRangesUsingBlock:block] - } - - unsafe fn getBytes_length_(self, buffer: *mut c_void, length: NSUInteger) { - msg_send![self, getBytes:buffer length:length] - } - - unsafe fn getBytes_range_(self, buffer: *mut c_void, range: NSRange) { - msg_send![self, getBytes:buffer range:range] - } - - unsafe fn subdataWithRange_(self, range: NSRange) -> id { - msg_send![self, subdataWithRange:range] - } - - unsafe fn rangeOfData_options_range_(self, dataToFind: id, options: NSDataSearchOptions, searchRange: NSRange) - -> NSRange { - msg_send![self, rangeOfData:dataToFind options:options range:searchRange] - } - - unsafe fn base64EncodedDataWithOptions_(self, options: NSDataBase64EncodingOptions) -> id { - msg_send![self, base64EncodedDataWithOptions:options] - } - - unsafe fn base64EncodedStringWithOptions_(self, options: NSDataBase64EncodingOptions) -> id { - msg_send![self, base64EncodedStringWithOptions:options] - } - - unsafe fn isEqualToData_(self, otherData: id) -> id { - msg_send![self, isEqualToData:otherData] - } - - unsafe fn length(self) -> NSUInteger { - msg_send![self, length] - } - - unsafe fn writeToFile_atomically_(self, path: id, atomically: BOOL) -> BOOL { - msg_send![self, writeToFile:path atomically:atomically] - } - - unsafe fn writeToFile_options_error_(self, path: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL { - msg_send![self, writeToFile:path options:mask error:errorPtr] - } - - unsafe fn writeToURL_atomically_(self, aURL: id, atomically: BOOL) -> BOOL { - msg_send![self, writeToURL:aURL atomically:atomically] - } - - unsafe fn writeToURL_options_error_(self, aURL: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL { - msg_send![self, writeToURL:aURL options:mask error:errorPtr] - } -} - -bitflags! { - pub struct NSDataReadingOptions: libc::c_ulonglong { - const NSDataReadingMappedIfSafe = 1 << 0; - const NSDataReadingUncached = 1 << 1; - const NSDataReadingMappedAlways = 1 << 3; - } -} - -bitflags! { - pub struct NSDataBase64EncodingOptions: libc::c_ulonglong { - const NSDataBase64Encoding64CharacterLineLength = 1 << 0; - const NSDataBase64Encoding76CharacterLineLength = 1 << 1; - const NSDataBase64EncodingEndLineWithCarriageReturn = 1 << 4; - const NSDataBase64EncodingEndLineWithLineFeed = 1 << 5; - } -} - -bitflags! { - pub struct NSDataBase64DecodingOptions: libc::c_ulonglong { - const NSDataBase64DecodingIgnoreUnknownCharacters = 1 << 0; - } -} - -bitflags! { - pub struct NSDataWritingOptions: libc::c_ulonglong { - const NSDataWritingAtomic = 1 << 0; - const NSDataWritingWithoutOverwriting = 1 << 1; - } -} - -bitflags! { - pub struct NSDataSearchOptions: libc::c_ulonglong { - const NSDataSearchBackwards = 1 << 0; - const NSDataSearchAnchored = 1 << 1; - } -} diff --git a/third_party/cargo/vendor/cocoa-0.20.1/.cargo-checksum.json b/third_party/cargo/vendor/cocoa-0.20.1/.cargo-checksum.json deleted file mode 100644 index e470ad0..0000000 --- a/third_party/cargo/vendor/cocoa-0.20.1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.lock":"9909380e3b48716dc2358036627337cea1a7357e0eb3e8e63b6252c074a6077e","Cargo.toml":"028039e35cdeff788575b44c5869857d10e71d7f96f5bbf6f5474acaa3e6aef5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"29542cb34adb016506822ef78bceacf1774dbe8c27818a4d47b7d7b71ed4e1ac","examples/color.rs":"5211a85ab9ec4cbb98f8f677de50bb2f1d300400f50226ebfd714d40b9d32485","examples/fullscreen.rs":"f8719268b6eb1d19078af347e02f9993c9d29633ef2d38dcc4fac26cbd731c2d","examples/hello_world.rs":"7efe2a29de4d4dfc1d8821f469e13b1456f72de478bab55f813d08d4e5aafd5c","examples/tab_view.rs":"e6a3187eeac2f46210994293c2db7756757f4cad07e519902fa994c6d5c1a7d6","src/appkit.rs":"a2ca0f7c86583be2bc5fed992bb86039bba9eca0586c981ff70091e2298e52cc","src/base.rs":"6c56d1758a9b0a7f8927771fe8b0bb43c6f19e4531bf9accecc786028eaad845","src/foundation.rs":"d3f14a7d1d20840cb00d52cc54df5c68a353b5ea925bd973d6bd27b4911d91b1","src/lib.rs":"ed6164b3e0fe68579218185267d79229a2989c86efce690d7273f779c5239ec3","src/macros.rs":"0de0a8ea9a23f03cad94266a92051c3be8ff3f8f7d7d60f95dafe6c663204d48","src/quartzcore.rs":"cb4f96b4b095e9d623346a42b1e119a5299bf2af73ed81256dd548c688d525e2","tests/foundation.rs":"728eb7dcc9edbfb43dcb6aa1ebcc391658a7d47846d94a71905bcedfce833260"},"package":"8f7b6f3f7f4f0b3ec5c5039aaa9e8c3cef97a7a480a400fd62944841314f293d"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cocoa-0.20.1/BUILD.bazel b/third_party/cargo/vendor/cocoa-0.20.1/BUILD.bazel deleted file mode 100644 index cd454cf..0000000 --- a/third_party/cargo/vendor/cocoa-0.20.1/BUILD.bazel +++ /dev/null @@ -1,70 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -# Unsupported target "color" with type "example" omitted - -# Unsupported target "fullscreen" with type "example" omitted - -# Unsupported target "hello_world" with type "example" omitted - -# Unsupported target "tab_view" with type "example" omitted - -rust_library( - name = "cocoa", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.20.1", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", - "//third_party/cargo/vendor/block-0.1.6:block", - "//third_party/cargo/vendor/core-foundation-0.7.0:core_foundation", - "//third_party/cargo/vendor/core-graphics-0.19.0:core_graphics", - "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", - "//third_party/cargo/vendor/libc-0.2.71:libc", - "//third_party/cargo/vendor/objc-0.2.7:objc", - ], -) - -# Unsupported target "foundation" with type "test" omitted diff --git a/third_party/cargo/vendor/cocoa-0.20.1/Cargo.lock b/third_party/cargo/vendor/cocoa-0.20.1/Cargo.lock deleted file mode 100644 index 157c6d0..0000000 --- a/third_party/cargo/vendor/cocoa-0.20.1/Cargo.lock +++ /dev/null @@ -1,93 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "cocoa" -version = "0.20.1" -dependencies = [ - "bitflags", - "block", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "core-foundation" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" - -[[package]] -name = "core-graphics" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd" -dependencies = [ - "bitflags", - "core-foundation", - "foreign-types", - "libc", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "libc" -version = "0.2.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] diff --git a/third_party/cargo/vendor/cocoa-0.20.1/Cargo.toml b/third_party/cargo/vendor/cocoa-0.20.1/Cargo.toml deleted file mode 100644 index e612514..0000000 --- a/third_party/cargo/vendor/cocoa-0.20.1/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "cocoa" -version = "0.20.1" -authors = ["The Servo Project Developers"] -description = "Bindings to Cocoa for macOS" -homepage = "https://github.com/servo/core-foundation-rs" -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/core-foundation-rs" -[dependencies.bitflags] -version = "1.0" - -[dependencies.block] -version = "0.1" - -[dependencies.core-foundation] -version = "0.7" - -[dependencies.core-graphics] -version = "0.19" - -[dependencies.foreign-types] -version = "0.3" - -[dependencies.libc] -version = "0.2" - -[dependencies.objc] -version = "0.2.3" diff --git a/third_party/cargo/vendor/cocoa-0.20.1/src/lib.rs b/third_party/cargo/vendor/cocoa-0.20.1/src/lib.rs deleted file mode 100644 index 4c5cce0..0000000 --- a/third_party/cargo/vendor/cocoa-0.20.1/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name = "cocoa"] -#![crate_type = "rlib"] - -#![allow(non_snake_case)] - -extern crate block; -#[macro_use] -extern crate bitflags; -extern crate core_foundation; -extern crate core_graphics; -extern crate foreign_types; -extern crate libc; -#[macro_use] -extern crate objc; - -#[cfg(target_os = "macos")] -pub mod appkit; -pub mod base; -pub mod foundation; -#[cfg(target_os = "macos")] -pub mod quartzcore; -#[macro_use] -mod macros; diff --git a/third_party/cargo/vendor/cocoa-0.20.1/tests/foundation.rs b/third_party/cargo/vendor/cocoa-0.20.1/tests/foundation.rs deleted file mode 100644 index c491501..0000000 --- a/third_party/cargo/vendor/cocoa-0.20.1/tests/foundation.rs +++ /dev/null @@ -1,195 +0,0 @@ -#[macro_use] -extern crate objc; -extern crate block; -extern crate cocoa; - -#[cfg(test)] -mod foundation { - mod nsstring { - use cocoa::foundation::NSString; - use cocoa::base::nil; - use std::slice; - use std::str; - - #[test] - fn test_utf8() { - let expected = "Iñtërnâtiônàlizætiøn"; - unsafe { - let built = NSString::alloc(nil).init_str(expected); - let bytes = built.UTF8String() as *const u8; - let objc_string = str::from_utf8(slice::from_raw_parts(bytes, built.len())) - .unwrap(); - assert_eq!(objc_string.len(), expected.len()); - assert_eq!(objc_string, expected); - } - } - - #[test] - fn test_string() { - let expected = "Hello World!"; - unsafe { - let built = NSString::alloc(nil).init_str(expected); - let bytes = built.UTF8String() as *const u8; - let objc_string = str::from_utf8(slice::from_raw_parts(bytes, built.len())) - .unwrap(); - assert_eq!(objc_string.len(), expected.len()); - assert_eq!(objc_string, expected); - } - } - - #[test] - fn test_length() { - let expected = "Hello!"; - unsafe { - let built = NSString::alloc(nil).init_str(expected); - assert_eq!(built.len(), expected.len()); - } - } - - #[test] - fn test_append_by_appending_string() { - let initial_str = "Iñtërnâtiônàlizætiøn"; - let to_append = "_more_strings"; - let expected = concat!("Iñtërnâtiônàlizætiøn", "_more_strings"); - unsafe { - let built = NSString::alloc(nil).init_str(initial_str); - let built_to_append = NSString::alloc(nil).init_str(to_append); - let append_string = built.stringByAppendingString_(built_to_append); - let bytes = append_string.UTF8String() as *const u8; - let objc_string = str::from_utf8(slice::from_raw_parts(bytes, append_string.len())) - .unwrap(); - assert_eq!(objc_string, expected); - } - } - } - - mod nsfastenumeration { - use std::str; - use std::slice; - use cocoa::foundation::{NSString, NSFastEnumeration}; - use cocoa::base::{id, nil}; - - #[test] - fn test_iter() { - unsafe { - let string = NSString::alloc(nil).init_str("this is a test string"); - let separator = NSString::alloc(nil).init_str(" "); - let components: id = msg_send![string, componentsSeparatedByString: separator]; - - let combined = components.iter() - .map(|s| { - let bytes = s.UTF8String() as *const u8; - str::from_utf8(slice::from_raw_parts(bytes, s.len())).unwrap() - }) - .fold(String::new(), |mut acc, s| { - acc.push_str(s); - acc - }); - - assert_eq!(combined, "thisisateststring"); - } - } - - #[test] - #[should_panic] - fn test_mutation() { - unsafe { - let string = NSString::alloc(nil).init_str("this is a test string"); - let separator = NSString::alloc(nil).init_str(" "); - let components: id = msg_send![string, componentsSeparatedByString: separator]; - let mut_components: id = msg_send![components, mutableCopy]; - let mut iter = mut_components.iter(); - iter.next(); - let () = msg_send![mut_components, removeObjectAtIndex:1]; - iter.next(); - } - } - } - - mod nsdictionary { - use block::ConcreteBlock; - use cocoa::foundation::{NSArray, NSComparisonResult, NSDictionary, NSFastEnumeration, - NSString}; - use cocoa::base::{id, nil}; - - #[test] - fn test_get() { - const KEY: &'static str = "The key"; - const VALUE: &'static str = "Some value"; - unsafe { - let key = NSString::alloc(nil).init_str(KEY); - let value = NSString::alloc(nil).init_str(VALUE); - let dict = NSDictionary::dictionaryWithObject_forKey_(nil, value, key); - - let retrieved_value = dict.objectForKey_(key); - assert!(retrieved_value.isEqualToString(VALUE)); - } - } - - #[test] - fn test_iter() { - let mkstr = |s| unsafe { NSString::alloc(nil).init_str(s) }; - let keys = vec!["a", "b", "c", "d", "e", "f"]; - let objects = vec!["1", "2", "3", "4", "5", "6"]; - unsafe { - use std::{slice, str}; - use std::cmp::{Ord, Ordering}; - - let keys_raw_vec = keys.clone().into_iter().map(&mkstr).collect::>(); - let objs_raw_vec = objects.clone().into_iter().map(&mkstr).collect::>(); - - let keys_array = NSArray::arrayWithObjects(nil, &keys_raw_vec); - let objs_array = NSArray::arrayWithObjects(nil, &objs_raw_vec); - - let dict = - NSDictionary::dictionaryWithObjects_forKeys_(nil, objs_array, keys_array); - - // NSDictionary does not store its contents in order of insertion, so ask for - // sorted iterators to ensure that each item is the same as its counterpart in - // the vector. - - fn compare_function(s0: &id, s1: &id) -> Ordering { - unsafe { - let (bytes0, len0) = (s0.UTF8String() as *const u8, s0.len()); - let (bytes1, len1) = (s1.UTF8String() as *const u8, s1.len()); - let (s0, s1) = (str::from_utf8(slice::from_raw_parts(bytes0, len0)).unwrap(), - str::from_utf8(slice::from_raw_parts(bytes1, len1)).unwrap()); - let (c0, c1) = (s0.chars().next().unwrap(), s1.chars().next().unwrap()); - c0.cmp(&c1) - } - } - - // First test cocoa sorting... - let mut comparator = ConcreteBlock::new(|s0: id, s1: id| { - match compare_function(&s0, &s1) { - Ordering::Less => NSComparisonResult::NSOrderedAscending, - Ordering::Equal => NSComparisonResult::NSOrderedSame, - Ordering::Greater => NSComparisonResult::NSOrderedDescending, - } - }); - - let associated_iter = keys.iter().zip(objects.iter()); - for (k_id, (k, v)) in dict.keysSortedByValueUsingComparator_(&mut *comparator) - .iter() - .zip(associated_iter) { - assert!(k_id.isEqualToString(k)); - let v_id = dict.objectForKey_(k_id); - assert!(v_id.isEqualToString(v)); - } - - // Then use rust sorting - let mut keys_arr = dict.allKeys().iter().collect::>(); - keys_arr.sort_by(compare_function); - for (k0, k1) in keys_arr.into_iter().zip(keys.iter()) { - assert!(k0.isEqualToString(k1)); - } - - let mut objects_arr = dict.allValues().iter().collect::>(); - objects_arr.sort_by(compare_function); - for (v0, v1) in objects_arr.into_iter().zip(objects.iter()) { - assert!(v0.isEqualToString(v1)); - } - } - } - } -} diff --git a/third_party/cargo/vendor/cocoa-0.20.2/.cargo-checksum.json b/third_party/cargo/vendor/cocoa-0.20.2/.cargo-checksum.json new file mode 100644 index 0000000..2b569bd --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.20.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.lock":"17552e04e6cec31119ef52d374ef62621931457714596bfb06f135f96018e95d","Cargo.toml":"90da28758c183a58f65615fc01f39edfc41103df8dc290ce555fa60d4ae90060","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"29542cb34adb016506822ef78bceacf1774dbe8c27818a4d47b7d7b71ed4e1ac","examples/color.rs":"5211a85ab9ec4cbb98f8f677de50bb2f1d300400f50226ebfd714d40b9d32485","examples/fullscreen.rs":"f8719268b6eb1d19078af347e02f9993c9d29633ef2d38dcc4fac26cbd731c2d","examples/hello_world.rs":"7efe2a29de4d4dfc1d8821f469e13b1456f72de478bab55f813d08d4e5aafd5c","examples/tab_view.rs":"e6a3187eeac2f46210994293c2db7756757f4cad07e519902fa994c6d5c1a7d6","src/appkit.rs":"a2ca0f7c86583be2bc5fed992bb86039bba9eca0586c981ff70091e2298e52cc","src/base.rs":"6c56d1758a9b0a7f8927771fe8b0bb43c6f19e4531bf9accecc786028eaad845","src/foundation.rs":"d3f14a7d1d20840cb00d52cc54df5c68a353b5ea925bd973d6bd27b4911d91b1","src/lib.rs":"ed6164b3e0fe68579218185267d79229a2989c86efce690d7273f779c5239ec3","src/macros.rs":"0de0a8ea9a23f03cad94266a92051c3be8ff3f8f7d7d60f95dafe6c663204d48","src/quartzcore.rs":"cb4f96b4b095e9d623346a42b1e119a5299bf2af73ed81256dd548c688d525e2","tests/foundation.rs":"728eb7dcc9edbfb43dcb6aa1ebcc391658a7d47846d94a71905bcedfce833260"},"package":"0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cocoa-0.20.2/BUILD.bazel b/third_party/cargo/vendor/cocoa-0.20.2/BUILD.bazel new file mode 100644 index 0000000..d22381c --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.20.2/BUILD.bazel @@ -0,0 +1,70 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "color" with type "example" omitted + +# Unsupported target "fullscreen" with type "example" omitted + +# Unsupported target "hello_world" with type "example" omitted + +# Unsupported target "tab_view" with type "example" omitted + +rust_library( + name = "cocoa", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.20.2", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/block-0.1.6:block", + "//third_party/cargo/vendor/core-foundation-0.7.0:core_foundation", + "//third_party/cargo/vendor/core-graphics-0.19.2:core_graphics", + "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", + "//third_party/cargo/vendor/libc-0.2.82:libc", + "//third_party/cargo/vendor/objc-0.2.7:objc", + ], +) + +# Unsupported target "foundation" with type "test" omitted diff --git a/third_party/cargo/vendor/cocoa-0.19.1/COPYRIGHT b/third_party/cargo/vendor/cocoa-0.20.2/COPYRIGHT similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/COPYRIGHT rename to third_party/cargo/vendor/cocoa-0.20.2/COPYRIGHT diff --git a/third_party/cargo/vendor/cocoa-0.20.2/Cargo.lock b/third_party/cargo/vendor/cocoa-0.20.2/Cargo.lock new file mode 100644 index 0000000..2e8e904 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.20.2/Cargo.lock @@ -0,0 +1,93 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "cocoa" +version = "0.20.2" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-graphics" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] diff --git a/third_party/cargo/vendor/cocoa-0.20.2/Cargo.toml b/third_party/cargo/vendor/cocoa-0.20.2/Cargo.toml new file mode 100644 index 0000000..a373785 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.20.2/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cocoa" +version = "0.20.2" +authors = ["The Servo Project Developers"] +description = "Bindings to Cocoa for macOS" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" +[dependencies.bitflags] +version = "1.0" + +[dependencies.block] +version = "0.1" + +[dependencies.core-foundation] +version = "0.7" + +[dependencies.core-graphics] +version = "0.19" + +[dependencies.foreign-types] +version = "0.3" + +[dependencies.libc] +version = "0.2" + +[dependencies.objc] +version = "0.2.3" diff --git a/third_party/cargo/vendor/cmake-0.1.44/LICENSE-APACHE b/third_party/cargo/vendor/cocoa-0.20.2/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/cmake-0.1.44/LICENSE-APACHE rename to third_party/cargo/vendor/cocoa-0.20.2/LICENSE-APACHE diff --git a/third_party/cargo/vendor/cocoa-0.19.1/LICENSE-MIT b/third_party/cargo/vendor/cocoa-0.20.2/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/LICENSE-MIT rename to third_party/cargo/vendor/cocoa-0.20.2/LICENSE-MIT diff --git a/third_party/cargo/vendor/cocoa-0.19.1/README.md b/third_party/cargo/vendor/cocoa-0.20.2/README.md similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/README.md rename to third_party/cargo/vendor/cocoa-0.20.2/README.md diff --git a/third_party/cargo/vendor/cocoa-0.19.1/examples/color.rs b/third_party/cargo/vendor/cocoa-0.20.2/examples/color.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/examples/color.rs rename to third_party/cargo/vendor/cocoa-0.20.2/examples/color.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/examples/fullscreen.rs b/third_party/cargo/vendor/cocoa-0.20.2/examples/fullscreen.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/examples/fullscreen.rs rename to third_party/cargo/vendor/cocoa-0.20.2/examples/fullscreen.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/examples/hello_world.rs b/third_party/cargo/vendor/cocoa-0.20.2/examples/hello_world.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/examples/hello_world.rs rename to third_party/cargo/vendor/cocoa-0.20.2/examples/hello_world.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/examples/tab_view.rs b/third_party/cargo/vendor/cocoa-0.20.2/examples/tab_view.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/examples/tab_view.rs rename to third_party/cargo/vendor/cocoa-0.20.2/examples/tab_view.rs diff --git a/third_party/cargo/vendor/cocoa-0.20.1/src/appkit.rs b/third_party/cargo/vendor/cocoa-0.20.2/src/appkit.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/src/appkit.rs rename to third_party/cargo/vendor/cocoa-0.20.2/src/appkit.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/src/base.rs b/third_party/cargo/vendor/cocoa-0.20.2/src/base.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/src/base.rs rename to third_party/cargo/vendor/cocoa-0.20.2/src/base.rs diff --git a/third_party/cargo/vendor/cocoa-0.20.1/src/foundation.rs b/third_party/cargo/vendor/cocoa-0.20.2/src/foundation.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/src/foundation.rs rename to third_party/cargo/vendor/cocoa-0.20.2/src/foundation.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/src/lib.rs b/third_party/cargo/vendor/cocoa-0.20.2/src/lib.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/src/lib.rs rename to third_party/cargo/vendor/cocoa-0.20.2/src/lib.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/src/macros.rs b/third_party/cargo/vendor/cocoa-0.20.2/src/macros.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/src/macros.rs rename to third_party/cargo/vendor/cocoa-0.20.2/src/macros.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/src/quartzcore.rs b/third_party/cargo/vendor/cocoa-0.20.2/src/quartzcore.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/src/quartzcore.rs rename to third_party/cargo/vendor/cocoa-0.20.2/src/quartzcore.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/tests/foundation.rs b/third_party/cargo/vendor/cocoa-0.20.2/tests/foundation.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/tests/foundation.rs rename to third_party/cargo/vendor/cocoa-0.20.2/tests/foundation.rs diff --git a/third_party/cargo/vendor/cocoa-0.24.0/.cargo-checksum.json b/third_party/cargo/vendor/cocoa-0.24.0/.cargo-checksum.json new file mode 100644 index 0000000..8c01f03 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.lock":"3a76cb5237c92762245517f919aa192f924dfcf9aaa84d9a8d12490f44235341","Cargo.toml":"5e844a3e0cac132df111a43a2a3cdbae0f6d9f750d6719f19bf2c7b82968bdce","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"29542cb34adb016506822ef78bceacf1774dbe8c27818a4d47b7d7b71ed4e1ac","examples/color.rs":"5211a85ab9ec4cbb98f8f677de50bb2f1d300400f50226ebfd714d40b9d32485","examples/fullscreen.rs":"f8719268b6eb1d19078af347e02f9993c9d29633ef2d38dcc4fac26cbd731c2d","examples/hello_world.rs":"7efe2a29de4d4dfc1d8821f469e13b1456f72de478bab55f813d08d4e5aafd5c","examples/tab_view.rs":"e6a3187eeac2f46210994293c2db7756757f4cad07e519902fa994c6d5c1a7d6","src/appkit.rs":"6dd0f01d7741edb1fe1ad948b836a754039e0b2cd07dfbfc9f0aabc4c403f6b3","src/base.rs":"71e17116d6a6160d35752b83cafd309cb7a25cdb7392f2f4d64664167cdfc38c","src/foundation.rs":"8032c22d2a17fa83ea006566ca6353a30697035d330e28e43dff43d277a7d7c7","src/lib.rs":"b6aeda6016c571ac2b5486709455106c4c1f1c0276a33811e23e13b029df75d9","src/macros.rs":"0de0a8ea9a23f03cad94266a92051c3be8ff3f8f7d7d60f95dafe6c663204d48","src/quartzcore.rs":"cb4f96b4b095e9d623346a42b1e119a5299bf2af73ed81256dd548c688d525e2"},"package":"6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cocoa-0.24.0/BUILD.bazel b/third_party/cargo/vendor/cocoa-0.24.0/BUILD.bazel new file mode 100644 index 0000000..2507677 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/BUILD.bazel @@ -0,0 +1,69 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "color" with type "example" omitted + +# Unsupported target "fullscreen" with type "example" omitted + +# Unsupported target "hello_world" with type "example" omitted + +# Unsupported target "tab_view" with type "example" omitted + +rust_library( + name = "cocoa", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.24.0", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/block-0.1.6:block", + "//third_party/cargo/vendor/cocoa-foundation-0.1.0:cocoa_foundation", + "//third_party/cargo/vendor/core-foundation-0.9.1:core_foundation", + "//third_party/cargo/vendor/core-graphics-0.22.2:core_graphics", + "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", + "//third_party/cargo/vendor/libc-0.2.82:libc", + "//third_party/cargo/vendor/objc-0.2.7:objc", + ], +) diff --git a/third_party/cargo/vendor/cocoa-0.20.1/COPYRIGHT b/third_party/cargo/vendor/cocoa-0.24.0/COPYRIGHT similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/COPYRIGHT rename to third_party/cargo/vendor/cocoa-0.24.0/COPYRIGHT diff --git a/third_party/cargo/vendor/cocoa-0.24.0/Cargo.lock b/third_party/cargo/vendor/cocoa-0.24.0/Cargo.lock new file mode 100644 index 0000000..34804d0 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/Cargo.lock @@ -0,0 +1,122 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "cocoa" +version = "0.24.0" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "core-foundation" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0af3b5e4601de3837c9332e29e0aae47a0d46ebfa246d12b82f564bac233393" + +[[package]] +name = "core-graphics" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc239bba52bab96649441699533a68de294a101533b0270b2d65aa402b29a7f9" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "libc" +version = "0.2.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] diff --git a/third_party/cargo/vendor/cocoa-0.24.0/Cargo.toml b/third_party/cargo/vendor/cocoa-0.24.0/Cargo.toml new file mode 100644 index 0000000..f46d1cf --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cocoa" +version = "0.24.0" +authors = ["The Servo Project Developers"] +description = "Bindings to Cocoa for macOS" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" +[dependencies.bitflags] +version = "1.0" + +[dependencies.block] +version = "0.1" + +[dependencies.cocoa-foundation] +version = "0.1" + +[dependencies.core-foundation] +version = "0.9" + +[dependencies.core-graphics] +version = "0.22" + +[dependencies.foreign-types] +version = "0.3" + +[dependencies.libc] +version = "0.2" + +[dependencies.objc] +version = "0.2.3" diff --git a/third_party/cargo/vendor/cocoa-0.19.1/LICENSE-APACHE b/third_party/cargo/vendor/cocoa-0.24.0/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/cocoa-0.19.1/LICENSE-APACHE rename to third_party/cargo/vendor/cocoa-0.24.0/LICENSE-APACHE diff --git a/third_party/cargo/vendor/cocoa-0.20.1/LICENSE-MIT b/third_party/cargo/vendor/cocoa-0.24.0/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/LICENSE-MIT rename to third_party/cargo/vendor/cocoa-0.24.0/LICENSE-MIT diff --git a/third_party/cargo/vendor/cocoa-0.20.1/README.md b/third_party/cargo/vendor/cocoa-0.24.0/README.md similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/README.md rename to third_party/cargo/vendor/cocoa-0.24.0/README.md diff --git a/third_party/cargo/vendor/cocoa-0.20.1/examples/color.rs b/third_party/cargo/vendor/cocoa-0.24.0/examples/color.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/examples/color.rs rename to third_party/cargo/vendor/cocoa-0.24.0/examples/color.rs diff --git a/third_party/cargo/vendor/cocoa-0.20.1/examples/fullscreen.rs b/third_party/cargo/vendor/cocoa-0.24.0/examples/fullscreen.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/examples/fullscreen.rs rename to third_party/cargo/vendor/cocoa-0.24.0/examples/fullscreen.rs diff --git a/third_party/cargo/vendor/cocoa-0.20.1/examples/hello_world.rs b/third_party/cargo/vendor/cocoa-0.24.0/examples/hello_world.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/examples/hello_world.rs rename to third_party/cargo/vendor/cocoa-0.24.0/examples/hello_world.rs diff --git a/third_party/cargo/vendor/cocoa-0.20.1/examples/tab_view.rs b/third_party/cargo/vendor/cocoa-0.24.0/examples/tab_view.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/examples/tab_view.rs rename to third_party/cargo/vendor/cocoa-0.24.0/examples/tab_view.rs diff --git a/third_party/cargo/vendor/cocoa-0.19.1/src/appkit.rs b/third_party/cargo/vendor/cocoa-0.24.0/src/appkit.rs similarity index 98% rename from third_party/cargo/vendor/cocoa-0.19.1/src/appkit.rs rename to third_party/cargo/vendor/cocoa-0.24.0/src/appkit.rs index 53afce4..6147af5 100644 --- a/third_party/cargo/vendor/cocoa-0.19.1/src/appkit.rs +++ b/third_party/cargo/vendor/cocoa-0.24.0/src/appkit.rs @@ -987,6 +987,7 @@ pub trait NSWindow: Sized { unsafe fn setLevel_(self, level: NSInteger); // Managing Key Status + unsafe fn isKeyWindow(self) -> BOOL; unsafe fn canBecomeKeyWindow(self) -> BOOL; unsafe fn makeKeyWindow(self); unsafe fn makeKeyAndOrderFront_(self, sender: id); @@ -1480,6 +1481,10 @@ impl NSWindow for id { // Managing Key Status + unsafe fn isKeyWindow(self) -> BOOL { + msg_send![self, isKeyWindow] + } + unsafe fn canBecomeKeyWindow(self) -> BOOL { msg_send![self, canBecomeKeyWindow] } @@ -1769,6 +1774,23 @@ impl NSWindow for id { // TODO: Constraint-Based Layouts } +#[repr(usize)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum NSViewLayerContentsPlacement { + NSViewLayerContentsPlacementScaleAxesIndependently = 0, + NSViewLayerContentsPlacementScaleProportionallyToFit = 1, + NSViewLayerContentsPlacementScaleProportionallyToFill = 2, + NSViewLayerContentsPlacementCenter = 3, + NSViewLayerContentsPlacementTop = 4, + NSViewLayerContentsPlacementTopRight = 5, + NSViewLayerContentsPlacementRight = 6, + NSViewLayerContentsPlacementBottomRight = 7, + NSViewLayerContentsPlacementBottom = 8, + NSViewLayerContentsPlacementBottomLeft = 9, + NSViewLayerContentsPlacementLeft = 10, + NSViewLayerContentsPlacementTopLeft = 11, +} + pub trait NSView: Sized { unsafe fn alloc(_: Self) -> id { msg_send![class!(NSView), alloc] @@ -1778,6 +1800,8 @@ pub trait NSView: Sized { unsafe fn initWithFrame_(self, frameRect: NSRect) -> id; unsafe fn bounds(self) -> NSRect; unsafe fn frame(self) -> NSRect; + unsafe fn setFrameSize(self, frameSize: NSSize); + unsafe fn setFrameOrigin(self, frameOrigin: NSPoint); unsafe fn display_(self); unsafe fn setWantsBestResolutionOpenGLSurface_(self, flag: BOOL); unsafe fn convertPoint_fromView_(self, point: NSPoint, view: id) -> NSPoint; @@ -1794,6 +1818,9 @@ pub trait NSView: Sized { unsafe fn widthAnchor(self) -> id; unsafe fn heightAnchor(self) -> id; unsafe fn convertRectToBacking(self, rect: NSRect) -> NSRect; + + unsafe fn layerContentsPlacement(self) -> NSViewLayerContentsPlacement; + unsafe fn setLayerContentsPlacement(self, placement: NSViewLayerContentsPlacement); } impl NSView for id { @@ -1813,6 +1840,14 @@ impl NSView for id { msg_send![self, frame] } + unsafe fn setFrameSize(self, frameSize: NSSize) { + msg_send![self, setFrameSize:frameSize] + } + + unsafe fn setFrameOrigin(self, frameOrigin: NSPoint) { + msg_send![self, setFrameOrigin:frameOrigin] + } + unsafe fn display_(self) { msg_send![self, display] } @@ -1868,6 +1903,14 @@ impl NSView for id { unsafe fn convertRectToBacking(self, rect: NSRect) -> NSRect { msg_send![self, convertRectToBacking:rect] } + + unsafe fn layerContentsPlacement(self) -> NSViewLayerContentsPlacement { + msg_send![self, layerContentsPlacement] + } + + unsafe fn setLayerContentsPlacement(self, placement: NSViewLayerContentsPlacement) { + msg_send![self, setLayerContentsPlacement: placement] + } } pub type NSAutoresizingMaskOptions = u64; @@ -2968,7 +3011,7 @@ pub trait NSButton: Sized { msg_send![class!(NSButton), alloc] } unsafe fn initWithFrame_(self, frameRect: NSRect) -> id; - unsafe fn setTarget_(self, target: id /* Instance */); + unsafe fn setTarget_(self, target: id /* Instance */); unsafe fn setAction_(self, selector: objc::runtime::Sel /* (Instance *) */); } @@ -3645,7 +3688,7 @@ pub trait NSTabView: Sized { unsafe fn allowsTruncatedLabels(self) -> BOOL; unsafe fn setAllowsTruncatedLabels_(self, allowTruncatedLabels:BOOL); unsafe fn setDelegate_(self, delegate:id); - unsafe fn delegate(self) -> id ; + unsafe fn delegate(self) -> id; unsafe fn tabViewAtPoint_(self, point:id) -> id; } diff --git a/third_party/cargo/vendor/cocoa-0.24.0/src/base.rs b/third_party/cargo/vendor/cocoa-0.24.0/src/base.rs new file mode 100644 index 0000000..39a0406 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/src/base.rs @@ -0,0 +1,11 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +pub use cocoa_foundation::base::*; diff --git a/third_party/cargo/vendor/cocoa-0.24.0/src/foundation.rs b/third_party/cargo/vendor/cocoa-0.24.0/src/foundation.rs new file mode 100644 index 0000000..3608d55 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/src/foundation.rs @@ -0,0 +1,10 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use cocoa_foundation::foundation::*; diff --git a/third_party/cargo/vendor/cocoa-0.24.0/src/lib.rs b/third_party/cargo/vendor/cocoa-0.24.0/src/lib.rs new file mode 100644 index 0000000..afc053a --- /dev/null +++ b/third_party/cargo/vendor/cocoa-0.24.0/src/lib.rs @@ -0,0 +1,33 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "cocoa"] +#![crate_type = "rlib"] + +#![allow(non_snake_case)] + +extern crate block; +#[macro_use] +extern crate bitflags; +extern crate core_foundation; +extern crate core_graphics; +extern crate cocoa_foundation; +extern crate foreign_types; +extern crate libc; +#[macro_use] +extern crate objc; + +#[cfg(target_os = "macos")] +pub mod appkit; +pub mod base; +pub mod foundation; +#[cfg(target_os = "macos")] +pub mod quartzcore; +#[macro_use] +mod macros; diff --git a/third_party/cargo/vendor/cocoa-0.20.1/src/macros.rs b/third_party/cargo/vendor/cocoa-0.24.0/src/macros.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/src/macros.rs rename to third_party/cargo/vendor/cocoa-0.24.0/src/macros.rs diff --git a/third_party/cargo/vendor/cocoa-0.20.1/src/quartzcore.rs b/third_party/cargo/vendor/cocoa-0.24.0/src/quartzcore.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/src/quartzcore.rs rename to third_party/cargo/vendor/cocoa-0.24.0/src/quartzcore.rs diff --git a/third_party/cargo/vendor/cocoa-foundation-0.1.0/.cargo-checksum.json b/third_party/cargo/vendor/cocoa-foundation-0.1.0/.cargo-checksum.json new file mode 100644 index 0000000..e2d9dae --- /dev/null +++ b/third_party/cargo/vendor/cocoa-foundation-0.1.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"73849af199374870f30fd6bc8b55b85f05ae3d3cb41a98bb660cc605cc80c5e2","src/base.rs":"6c56d1758a9b0a7f8927771fe8b0bb43c6f19e4531bf9accecc786028eaad845","src/foundation.rs":"056daed1c9eb17772544397960bd196d1c8de1c0d13705372b57bd71843fcc74","src/lib.rs":"7f2e7bce9f1727acdd88b7cff604130cab04bf4b58a58f1d8c684a543412a330","tests/foundation.rs":"ef38d1aabe9534d95e0c5a6440f4f0465eeacd151b1ae5108df57810fb0f3ff8"},"package":"7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cocoa-foundation-0.1.0/BUILD.bazel b/third_party/cargo/vendor/cocoa-foundation-0.1.0/BUILD.bazel new file mode 100644 index 0000000..808a49d --- /dev/null +++ b/third_party/cargo/vendor/cocoa-foundation-0.1.0/BUILD.bazel @@ -0,0 +1,62 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "cocoa_foundation", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.1.0", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/block-0.1.6:block", + "//third_party/cargo/vendor/core-foundation-0.9.1:core_foundation", + "//third_party/cargo/vendor/core-graphics-types-0.1.1:core_graphics_types", + "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", + "//third_party/cargo/vendor/libc-0.2.82:libc", + "//third_party/cargo/vendor/objc-0.2.7:objc", + ], +) + +# Unsupported target "foundation" with type "test" omitted diff --git a/third_party/cargo/vendor/cocoa-foundation-0.1.0/Cargo.toml b/third_party/cargo/vendor/cocoa-foundation-0.1.0/Cargo.toml new file mode 100644 index 0000000..0912659 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-foundation-0.1.0/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cocoa-foundation" +version = "0.1.0" +authors = ["The Servo Project Developers"] +description = "Bindings to Cocoa Foundation for macOS" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" +[dependencies.bitflags] +version = "1.0" + +[dependencies.block] +version = "0.1" + +[dependencies.core-foundation] +version = "0.9" + +[dependencies.core-graphics-types] +version = "0.1" + +[dependencies.foreign-types] +version = "0.3" + +[dependencies.libc] +version = "0.2" + +[dependencies.objc] +version = "0.2.3" diff --git a/third_party/cargo/vendor/cocoa-0.20.1/src/base.rs b/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/base.rs similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/src/base.rs rename to third_party/cargo/vendor/cocoa-foundation-0.1.0/src/base.rs diff --git a/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/foundation.rs b/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/foundation.rs new file mode 100644 index 0000000..5ea1bf6 --- /dev/null +++ b/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/foundation.rs @@ -0,0 +1,1376 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use std::ptr; +use std::os::raw::c_void; +use base::{id, BOOL, NO, SEL, nil}; +use block::Block; +use libc; + + +#[cfg(target_pointer_width = "32")] +pub type NSInteger = libc::c_int; +#[cfg(target_pointer_width = "32")] +pub type NSUInteger = libc::c_uint; + +#[cfg(target_pointer_width = "64")] +pub type NSInteger = libc::c_long; +#[cfg(target_pointer_width = "64")] +pub type NSUInteger = libc::c_ulong; + +pub const NSIntegerMax: NSInteger = NSInteger::max_value(); +pub const NSNotFound: NSInteger = NSIntegerMax; + +const UTF8_ENCODING: usize = 4; + +#[cfg(target_os = "macos")] +mod macos { + use std::mem; + use base::id; + use core_graphics_types::base::CGFloat; + use core_graphics_types::geometry::CGRect; + use objc; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct NSPoint { + pub x: CGFloat, + pub y: CGFloat, + } + + impl NSPoint { + #[inline] + pub fn new(x: CGFloat, y: CGFloat) -> NSPoint { + NSPoint { + x: x, + y: y, + } + } + } + + unsafe impl objc::Encode for NSPoint { + fn encode() -> objc::Encoding { + let encoding = format!("{{CGPoint={}{}}}", + CGFloat::encode().as_str(), + CGFloat::encode().as_str()); + unsafe { objc::Encoding::from_str(&encoding) } + } + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct NSSize { + pub width: CGFloat, + pub height: CGFloat, + } + + impl NSSize { + #[inline] + pub fn new(width: CGFloat, height: CGFloat) -> NSSize { + NSSize { + width: width, + height: height, + } + } + } + + unsafe impl objc::Encode for NSSize { + fn encode() -> objc::Encoding { + let encoding = format!("{{CGSize={}{}}}", + CGFloat::encode().as_str(), + CGFloat::encode().as_str()); + unsafe { objc::Encoding::from_str(&encoding) } + } + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct NSRect { + pub origin: NSPoint, + pub size: NSSize, + } + + impl NSRect { + #[inline] + pub fn new(origin: NSPoint, size: NSSize) -> NSRect { + NSRect { + origin: origin, + size: size + } + } + + #[inline] + pub fn as_CGRect(&self) -> &CGRect { + unsafe { + mem::transmute::<&NSRect, &CGRect>(self) + } + } + + #[inline] + pub fn inset(&self, x: CGFloat, y: CGFloat) -> NSRect { + unsafe { + NSInsetRect(*self, x, y) + } + } + } + + unsafe impl objc::Encode for NSRect { + fn encode() -> objc::Encoding { + let encoding = format!("{{CGRect={}{}}}", + NSPoint::encode().as_str(), + NSSize::encode().as_str()); + unsafe { objc::Encoding::from_str(&encoding) } + } + } + + // Same as CGRectEdge + #[repr(u32)] + pub enum NSRectEdge { + NSRectMinXEdge, + NSRectMinYEdge, + NSRectMaxXEdge, + NSRectMaxYEdge, + } + + #[link(name = "Foundation", kind = "framework")] + extern { + fn NSInsetRect(rect: NSRect, x: CGFloat, y: CGFloat) -> NSRect; + } + + pub trait NSValue: Sized { + unsafe fn valueWithPoint(_: Self, point: NSPoint) -> id { + msg_send![class!(NSValue), valueWithPoint:point] + } + + unsafe fn valueWithSize(_: Self, size: NSSize) -> id { + msg_send![class!(NSValue), valueWithSize:size] + } + } + + impl NSValue for id { + } +} + +#[cfg(target_os = "macos")] +pub use self::macos::*; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct NSRange { + pub location: NSUInteger, + pub length: NSUInteger, +} + +impl NSRange { + #[inline] + pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange { + NSRange { + location: location, + length: length + } + } +} + +#[link(name = "Foundation", kind = "framework")] +extern { + pub static NSDefaultRunLoopMode: id; +} + +pub trait NSAutoreleasePool: Sized { + unsafe fn new(_: Self) -> id { + msg_send![class!(NSAutoreleasePool), new] + } + + unsafe fn autorelease(self) -> Self; + unsafe fn drain(self); +} + +impl NSAutoreleasePool for id { + unsafe fn autorelease(self) -> id { + msg_send![self, autorelease] + } + + unsafe fn drain(self) { + msg_send![self, drain] + } +} + + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct NSOperatingSystemVersion { + pub majorVersion: NSUInteger, + pub minorVersion: NSUInteger, + pub patchVersion: NSUInteger, +} + +impl NSOperatingSystemVersion { + #[inline] + pub fn new(majorVersion: NSUInteger, minorVersion: NSUInteger, patchVersion: NSUInteger) -> NSOperatingSystemVersion { + NSOperatingSystemVersion { + majorVersion: majorVersion, + minorVersion: minorVersion, + patchVersion: patchVersion + } + } +} + + +pub trait NSProcessInfo: Sized { + unsafe fn processInfo(_: Self) -> id { + msg_send![class!(NSProcessInfo), processInfo] + } + + unsafe fn processName(self) -> id; + unsafe fn operatingSystemVersion(self) -> NSOperatingSystemVersion; + unsafe fn isOperatingSystemAtLeastVersion(self, version: NSOperatingSystemVersion) -> bool; +} + +impl NSProcessInfo for id { + unsafe fn processName(self) -> id { + msg_send![self, processName] + } + + unsafe fn operatingSystemVersion(self) -> NSOperatingSystemVersion { + msg_send![self, operatingSystemVersion] + } + + unsafe fn isOperatingSystemAtLeastVersion(self, version: NSOperatingSystemVersion) -> bool { + msg_send![self, isOperatingSystemAtLeastVersion: version] + } +} + +pub type NSTimeInterval = libc::c_double; + +pub trait NSArray: Sized { + unsafe fn array(_: Self) -> id { + msg_send![class!(NSArray), array] + } + + unsafe fn arrayWithObjects(_: Self, objects: &[id]) -> id { + msg_send![class!(NSArray), arrayWithObjects:objects.as_ptr() + count:objects.len()] + } + + unsafe fn arrayWithObject(_: Self, object: id) -> id { + msg_send![class!(NSArray), arrayWithObject:object] + } + + unsafe fn init(self) -> id; + + unsafe fn count(self) -> NSUInteger; + + unsafe fn arrayByAddingObjectFromArray(self, object: id) -> id; + unsafe fn arrayByAddingObjectsFromArray(self, objects: id) -> id; + unsafe fn objectAtIndex(self, index: NSUInteger) -> id; +} + +impl NSArray for id { + unsafe fn init(self) -> id { + msg_send![self, init] + } + + unsafe fn count(self) -> NSUInteger { + msg_send![self, count] + } + + unsafe fn arrayByAddingObjectFromArray(self, object: id) -> id { + msg_send![self, arrayByAddingObjectFromArray:object] + } + + unsafe fn arrayByAddingObjectsFromArray(self, objects: id) -> id { + msg_send![self, arrayByAddingObjectsFromArray:objects] + } + + unsafe fn objectAtIndex(self, index: NSUInteger) -> id { + msg_send![self, objectAtIndex:index] + } +} + +pub trait NSDictionary: Sized { + unsafe fn dictionary(_: Self) -> id { + msg_send![class!(NSDictionary), dictionary] + } + + unsafe fn dictionaryWithContentsOfFile_(_: Self, path: id) -> id { + msg_send![class!(NSDictionary), dictionaryWithContentsOfFile:path] + } + + unsafe fn dictionaryWithContentsOfURL_(_: Self, aURL: id) -> id { + msg_send![class!(NSDictionary), dictionaryWithContentsOfURL:aURL] + } + + unsafe fn dictionaryWithDictionary_(_: Self, otherDictionary: id) -> id { + msg_send![class!(NSDictionary), dictionaryWithDictionary:otherDictionary] + } + + unsafe fn dictionaryWithObject_forKey_(_: Self, anObject: id, aKey: id) -> id { + msg_send![class!(NSDictionary), dictionaryWithObject:anObject forKey:aKey] + } + + unsafe fn dictionaryWithObjects_forKeys_(_: Self, objects: id, keys: id) -> id { + msg_send![class!(NSDictionary), dictionaryWithObjects:objects forKeys:keys] + } + + unsafe fn dictionaryWithObjects_forKeys_count_(_: Self, objects: *const id, keys: *const id, count: NSUInteger) -> id { + msg_send![class!(NSDictionary), dictionaryWithObjects:objects forKeys:keys count:count] + } + + unsafe fn dictionaryWithObjectsAndKeys_(_: Self, firstObject: id) -> id { + msg_send![class!(NSDictionary), dictionaryWithObjectsAndKeys:firstObject] + } + + unsafe fn init(self) -> id; + unsafe fn initWithContentsOfFile_(self, path: id) -> id; + unsafe fn initWithContentsOfURL_(self, aURL: id) -> id; + unsafe fn initWithDictionary_(self, otherDicitonary: id) -> id; + unsafe fn initWithDictionary_copyItems_(self, otherDicitonary: id, flag: BOOL) -> id; + unsafe fn initWithObjects_forKeys_(self, objects: id, keys: id) -> id; + unsafe fn initWithObjects_forKeys_count_(self, objects: id, keys: id, count: NSUInteger) -> id; + unsafe fn initWithObjectsAndKeys_(self, firstObject: id) -> id; + + unsafe fn sharedKeySetForKeys_(_: Self, keys: id) -> id { + msg_send![class!(NSDictionary), sharedKeySetForKeys:keys] + } + + unsafe fn count(self) -> NSUInteger; + + unsafe fn isEqualToDictionary_(self, otherDictionary: id) -> BOOL; + + unsafe fn allKeys(self) -> id; + unsafe fn allKeysForObject_(self, anObject: id) -> id; + unsafe fn allValues(self) -> id; + unsafe fn objectForKey_(self, aKey: id) -> id; + unsafe fn objectForKeyedSubscript_(self, key: id) -> id; + unsafe fn objectsForKeys_notFoundMarker_(self, keys: id, anObject: id) -> id; + unsafe fn valueForKey_(self, key: id) -> id; + + unsafe fn keyEnumerator(self) -> id; + unsafe fn objectEnumerator(self) -> id; + unsafe fn enumerateKeysAndObjectsUsingBlock_(self, block: *mut Block<(id, id, *mut BOOL), ()>); + unsafe fn enumerateKeysAndObjectsWithOptions_usingBlock_(self, opts: NSEnumerationOptions, + block: *mut Block<(id, id, *mut BOOL), ()>); + + unsafe fn keysSortedByValueUsingSelector_(self, comparator: SEL) -> id; + unsafe fn keysSortedByValueUsingComparator_(self, cmptr: NSComparator) -> id; + unsafe fn keysSortedByValueWithOptions_usingComparator_(self, opts: NSEnumerationOptions, cmptr: NSComparator) -> id; + + unsafe fn keysOfEntriesPassingTest_(self, predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id; + unsafe fn keysOfEntriesWithOptions_PassingTest_(self, opts: NSEnumerationOptions, + predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id; + + unsafe fn writeToFile_atomically_(self, path: id, flag: BOOL) -> BOOL; + unsafe fn writeToURL_atomically_(self, aURL: id, flag: BOOL) -> BOOL; + + unsafe fn fileCreationDate(self) -> id; + unsafe fn fileExtensionHidden(self) -> BOOL; + unsafe fn fileGroupOwnerAccountID(self) -> id; + unsafe fn fileGroupOwnerAccountName(self) -> id; + unsafe fn fileIsAppendOnly(self) -> BOOL; + unsafe fn fileIsImmutable(self) -> BOOL; + unsafe fn fileModificationDate(self) -> id; + unsafe fn fileOwnerAccountID(self) -> id; + unsafe fn fileOwnerAccountName(self) -> id; + unsafe fn filePosixPermissions(self) -> NSUInteger; + unsafe fn fileSize(self) -> libc::c_ulonglong; + unsafe fn fileSystemFileNumber(self) -> NSUInteger; + unsafe fn fileSystemNumber(self) -> NSInteger; + unsafe fn fileType(self) -> id; + + unsafe fn description(self) -> id; + unsafe fn descriptionInStringsFileFormat(self) -> id; + unsafe fn descriptionWithLocale_(self, locale: id) -> id; + unsafe fn descriptionWithLocale_indent_(self, locale: id, indent: NSUInteger) -> id; +} + +impl NSDictionary for id { + unsafe fn init(self) -> id { + msg_send![self, init] + } + + unsafe fn initWithContentsOfFile_(self, path: id) -> id { + msg_send![self, initWithContentsOfFile:path] + } + + unsafe fn initWithContentsOfURL_(self, aURL: id) -> id { + msg_send![self, initWithContentsOfURL:aURL] + } + + unsafe fn initWithDictionary_(self, otherDictionary: id) -> id { + msg_send![self, initWithDictionary:otherDictionary] + } + + unsafe fn initWithDictionary_copyItems_(self, otherDictionary: id, flag: BOOL) -> id { + msg_send![self, initWithDictionary:otherDictionary copyItems:flag] + } + + unsafe fn initWithObjects_forKeys_(self, objects: id, keys: id) -> id { + msg_send![self, initWithObjects:objects forKeys:keys] + } + + unsafe fn initWithObjects_forKeys_count_(self, objects: id, keys: id, count: NSUInteger) -> id { + msg_send![self, initWithObjects:objects forKeys:keys count:count] + } + + unsafe fn initWithObjectsAndKeys_(self, firstObject: id) -> id { + msg_send![self, initWithObjectsAndKeys:firstObject] + } + + unsafe fn count(self) -> NSUInteger { + msg_send![self, count] + } + + unsafe fn isEqualToDictionary_(self, otherDictionary: id) -> BOOL { + msg_send![self, isEqualToDictionary:otherDictionary] + } + + unsafe fn allKeys(self) -> id { + msg_send![self, allKeys] + } + + unsafe fn allKeysForObject_(self, anObject: id) -> id { + msg_send![self, allKeysForObject:anObject] + } + + unsafe fn allValues(self) -> id { + msg_send![self, allValues] + } + + unsafe fn objectForKey_(self, aKey: id) -> id { + msg_send![self, objectForKey:aKey] + } + + unsafe fn objectForKeyedSubscript_(self, key: id) -> id { + msg_send![self, objectForKeyedSubscript:key] + } + + unsafe fn objectsForKeys_notFoundMarker_(self, keys: id, anObject: id) -> id { + msg_send![self, objectsForKeys:keys notFoundMarker:anObject] + } + + unsafe fn valueForKey_(self, key: id) -> id { + msg_send![self, valueForKey:key] + } + + unsafe fn keyEnumerator(self) -> id { + msg_send![self, keyEnumerator] + } + + unsafe fn objectEnumerator(self) -> id { + msg_send![self, objectEnumerator] + } + + unsafe fn enumerateKeysAndObjectsUsingBlock_(self, block: *mut Block<(id, id, *mut BOOL), ()>) { + msg_send![self, enumerateKeysAndObjectsUsingBlock:block] + } + + unsafe fn enumerateKeysAndObjectsWithOptions_usingBlock_(self, opts: NSEnumerationOptions, + block: *mut Block<(id, id, *mut BOOL), ()>) { + msg_send![self, enumerateKeysAndObjectsWithOptions:opts usingBlock:block] + } + + unsafe fn keysSortedByValueUsingSelector_(self, comparator: SEL) -> id { + msg_send![self, keysSortedByValueUsingSelector:comparator] + } + + unsafe fn keysSortedByValueUsingComparator_(self, cmptr: NSComparator) -> id { + msg_send![self, keysSortedByValueUsingComparator:cmptr] + } + + unsafe fn keysSortedByValueWithOptions_usingComparator_(self, opts: NSEnumerationOptions, cmptr: NSComparator) -> id { + let rv: id = msg_send![self, keysSortedByValueWithOptions:opts usingComparator:cmptr]; + rv + } + + unsafe fn keysOfEntriesPassingTest_(self, predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id { + msg_send![self, keysOfEntriesPassingTest:predicate] + } + + unsafe fn keysOfEntriesWithOptions_PassingTest_(self, opts: NSEnumerationOptions, + predicate: *mut Block<(id, id, *mut BOOL), BOOL>) -> id { + msg_send![self, keysOfEntriesWithOptions:opts PassingTest:predicate] + } + + unsafe fn writeToFile_atomically_(self, path: id, flag: BOOL) -> BOOL { + msg_send![self, writeToFile:path atomically:flag] + } + + unsafe fn writeToURL_atomically_(self, aURL: id, flag: BOOL) -> BOOL { + msg_send![self, writeToURL:aURL atomically:flag] + } + + unsafe fn fileCreationDate(self) -> id { + msg_send![self, fileCreationDate] + } + + unsafe fn fileExtensionHidden(self) -> BOOL { + msg_send![self, fileExtensionHidden] + } + + unsafe fn fileGroupOwnerAccountID(self) -> id { + msg_send![self, fileGroupOwnerAccountID] + } + + unsafe fn fileGroupOwnerAccountName(self) -> id { + msg_send![self, fileGroupOwnerAccountName] + } + + unsafe fn fileIsAppendOnly(self) -> BOOL { + msg_send![self, fileIsAppendOnly] + } + + unsafe fn fileIsImmutable(self) -> BOOL { + msg_send![self, fileIsImmutable] + } + + unsafe fn fileModificationDate(self) -> id { + msg_send![self, fileModificationDate] + } + + unsafe fn fileOwnerAccountID(self) -> id { + msg_send![self, fileOwnerAccountID] + } + + unsafe fn fileOwnerAccountName(self) -> id { + msg_send![self, fileOwnerAccountName] + } + + unsafe fn filePosixPermissions(self) -> NSUInteger { + msg_send![self, filePosixPermissions] + } + + unsafe fn fileSize(self) -> libc::c_ulonglong { + msg_send![self, fileSize] + } + + unsafe fn fileSystemFileNumber(self) -> NSUInteger { + msg_send![self, fileSystemFileNumber] + } + + unsafe fn fileSystemNumber(self) -> NSInteger { + msg_send![self, fileSystemNumber] + } + + unsafe fn fileType(self) -> id { + msg_send![self, fileType] + } + + unsafe fn description(self) -> id { + msg_send![self, description] + } + + unsafe fn descriptionInStringsFileFormat(self) -> id { + msg_send![self, descriptionInStringsFileFormat] + } + + unsafe fn descriptionWithLocale_(self, locale: id) -> id { + msg_send![self, descriptionWithLocale:locale] + } + + unsafe fn descriptionWithLocale_indent_(self, locale: id, indent: NSUInteger) -> id { + msg_send![self, descriptionWithLocale:locale indent:indent] + } +} + +bitflags! { + pub struct NSEnumerationOptions: libc::c_ulonglong { + const NSEnumerationConcurrent = 1 << 0; + const NSEnumerationReverse = 1 << 1; + } +} + +pub type NSComparator = *mut Block<(id, id), NSComparisonResult>; + +#[repr(isize)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum NSComparisonResult { + NSOrderedAscending = -1, + NSOrderedSame = 0, + NSOrderedDescending = 1 +} + +pub trait NSString: Sized { + unsafe fn alloc(_: Self) -> id { + msg_send![class!(NSString), alloc] + } + + unsafe fn stringByAppendingString_(self, other: id) -> id; + unsafe fn init_str(self, string: &str) -> Self; + unsafe fn UTF8String(self) -> *const libc::c_char; + unsafe fn len(self) -> usize; + unsafe fn isEqualToString(self, &str) -> bool; + unsafe fn substringWithRange(self, range: NSRange) -> id; +} + +impl NSString for id { + unsafe fn isEqualToString(self, other: &str) -> bool { + let other = NSString::alloc(nil).init_str(other); + let rv: BOOL = msg_send![self, isEqualToString:other]; + rv != NO + } + + unsafe fn stringByAppendingString_(self, other: id) -> id { + msg_send![self, stringByAppendingString:other] + } + + unsafe fn init_str(self, string: &str) -> id { + return msg_send![self, + initWithBytes:string.as_ptr() + length:string.len() + encoding:UTF8_ENCODING as id]; + } + + unsafe fn len(self) -> usize { + msg_send![self, lengthOfBytesUsingEncoding:UTF8_ENCODING] + } + + unsafe fn UTF8String(self) -> *const libc::c_char { + msg_send![self, UTF8String] + } + + unsafe fn substringWithRange(self, range: NSRange) -> id { + msg_send![self, substringWithRange:range] + } +} + +pub trait NSDate: Sized { + unsafe fn distantPast(_: Self) -> id { + msg_send![class!(NSDate), distantPast] + } + + unsafe fn distantFuture(_: Self) -> id { + msg_send![class!(NSDate), distantFuture] + } +} + +impl NSDate for id { + +} + +#[repr(C)] +struct NSFastEnumerationState { + pub state: libc::c_ulong, + pub items_ptr: *mut id, + pub mutations_ptr: *mut libc::c_ulong, + pub extra: [libc::c_ulong; 5] +} + +const NS_FAST_ENUM_BUF_SIZE: usize = 16; + +pub struct NSFastIterator { + state: NSFastEnumerationState, + buffer: [id; NS_FAST_ENUM_BUF_SIZE], + mut_val: Option, + len: usize, + idx: usize, + object: id +} + +impl Iterator for NSFastIterator { + type Item = id; + + fn next(&mut self) -> Option { + if self.idx >= self.len { + self.len = unsafe { + msg_send![self.object, countByEnumeratingWithState:&mut self.state objects:self.buffer.as_mut_ptr() count:NS_FAST_ENUM_BUF_SIZE] + }; + self.idx = 0; + } + + let new_mut = unsafe { + *self.state.mutations_ptr + }; + + if let Some(old_mut) = self.mut_val { + assert!(old_mut == new_mut, "The collection was mutated while being enumerated"); + } + + if self.idx < self.len { + let object = unsafe { + *self.state.items_ptr.offset(self.idx as isize) + }; + self.mut_val = Some(new_mut); + self.idx += 1; + Some(object) + } else { + None + } + } +} + +pub trait NSFastEnumeration: Sized { + unsafe fn iter(self) -> NSFastIterator; +} + +impl NSFastEnumeration for id { + unsafe fn iter(self) -> NSFastIterator { + NSFastIterator { + state: NSFastEnumerationState { + state: 0, + items_ptr: ptr::null_mut(), + mutations_ptr: ptr::null_mut(), + extra: [0; 5] + }, + buffer: [nil; NS_FAST_ENUM_BUF_SIZE], + mut_val: None, + len: 0, + idx: 0, + object: self + } + } +} + +pub trait NSRunLoop: Sized { + unsafe fn currentRunLoop() -> Self; + + unsafe fn performSelector_target_argument_order_modes_(self, + aSelector: SEL, + target: id, + anArgument: id, + order: NSUInteger, + modes: id); +} + +impl NSRunLoop for id { + unsafe fn currentRunLoop() -> id { + msg_send![class!(NSRunLoop), currentRunLoop] + } + + unsafe fn performSelector_target_argument_order_modes_(self, + aSelector: SEL, + target: id, + anArgument: id, + order: NSUInteger, + modes: id) { + msg_send![self, performSelector:aSelector + target:target + argument:anArgument + order:order + modes:modes] + } +} + +bitflags! { + pub struct NSURLBookmarkCreationOptions: NSUInteger { + const NSURLBookmarkCreationPreferFileIDResolution = 1 << 8; + const NSURLBookmarkCreationMinimalBookmark = 1 << 9; + const NSURLBookmarkCreationSuitableForBookmarkFile = 1 << 10; + const NSURLBookmarkCreationWithSecurityScope = 1 << 11; + const NSURLBookmarkCreationSecurityScopeAllowOnlyReadAccess = 1 << 12; + } +} + +pub type NSURLBookmarkFileCreationOptions = NSURLBookmarkCreationOptions; + +bitflags! { + pub struct NSURLBookmarkResolutionOptions: NSUInteger { + const NSURLBookmarkResolutionWithoutUI = 1 << 8; + const NSURLBookmarkResolutionWithoutMounting = 1 << 9; + const NSURLBookmarkResolutionWithSecurityScope = 1 << 10; + } +} + + +pub trait NSURL: Sized { + unsafe fn alloc(_: Self) -> id; + + unsafe fn URLWithString_(_:Self, string: id) -> id; + unsafe fn initWithString_(self, string: id) -> id; + unsafe fn URLWithString_relativeToURL_(_:Self, string: id, url: id) -> id; + unsafe fn initWithString_relativeToURL_(self, string: id, url: id) -> id; + unsafe fn fileURLWithPath_isDirectory_(_:Self, path: id, is_dir: BOOL) -> id; + unsafe fn initFileURLWithPath_isDirectory_(self, path: id, is_dir: BOOL) -> id; + unsafe fn fileURLWithPath_relativeToURL_(_:Self, path: id, url: id) -> id; + unsafe fn initFileURLWithPath_relativeToURL_(self, path: id, url: id) -> id; + unsafe fn fileURLWithPath_isDirectory_relativeToURL_(_:Self, path: id, is_dir: BOOL, url: id) -> id; + unsafe fn initFileURLWithPath_isDirectory_relativeToURL_(self, path: id, is_dir: BOOL, url: id) -> id; + unsafe fn fileURLWithPath_(_:Self, path: id) -> id; + unsafe fn initFileURLWithPath_(self, path: id) -> id; + unsafe fn fileURLWithPathComponents_(_:Self, path_components: id /* (NSArray*) */) -> id; + unsafe fn URLByResolvingAliasFileAtURL_options_error_(_:Self, url: id, options: NSURLBookmarkResolutionOptions, error: *mut id /* (NSError _Nullable) */) -> id; + unsafe fn URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(_:Self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id; + unsafe fn initByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id; + // unsafe fn fileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ + // unsafe fn getFileSystemRepresentation_maxLength_ + // unsafe fn initFileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ + unsafe fn absoluteURLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id; + unsafe fn initAbsoluteURLWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id; + unsafe fn URLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id; + unsafe fn initWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id; + unsafe fn dataRepresentation(self) -> id /* (NSData) */; + + unsafe fn isEqual_(self, id: id) -> BOOL; + + unsafe fn checkResourceIsReachableAndReturnError_(self, error: id /* (NSError _Nullable) */) -> BOOL; + unsafe fn isFileReferenceURL(self) -> BOOL; + unsafe fn isFileURL(self) -> BOOL; + + unsafe fn absoluteString(self) -> id /* (NSString) */; + unsafe fn absoluteURL(self) -> id /* (NSURL) */; + unsafe fn baseURL(self) -> id /* (NSURL) */; + // unsafe fn fileSystemRepresentation + unsafe fn fragment(self) -> id /* (NSString) */; + unsafe fn host(self) -> id /* (NSString) */; + unsafe fn lastPathComponent(self) -> id /* (NSString) */; + unsafe fn parameterString(self) -> id /* (NSString) */; + unsafe fn password(self) -> id /* (NSString) */; + unsafe fn path(self) -> id /* (NSString) */; + unsafe fn pathComponents(self) -> id /* (NSArray) */; + unsafe fn pathExtension(self) -> id /* (NSString) */; + unsafe fn port(self) -> id /* (NSNumber) */; + unsafe fn query(self) -> id /* (NSString) */; + unsafe fn relativePath(self) -> id /* (NSString) */; + unsafe fn relativeString(self) -> id /* (NSString) */; + unsafe fn resourceSpecifier(self) -> id /* (NSString) */; + unsafe fn scheme(self) -> id /* (NSString) */; + unsafe fn standardizedURL(self) -> id /* (NSURL) */; + unsafe fn user(self) -> id /* (NSString) */; + + // unsafe fn resourceValuesForKeys_error_ + // unsafe fn getResourceValue_forKey_error_ + // unsafe fn setResourceValue_forKey_error_ + // unsafe fn setResourceValues_error_ + // unsafe fn removeAllCachedResourceValues + // unsafe fn removeCachedResourceValueForKey_ + // unsafe fn setTemporaryResourceValue_forKey_ + unsafe fn NSURLResourceKey(self) -> id /* (NSString) */; + + unsafe fn filePathURL(self) -> id; + unsafe fn fileReferenceURL(self) -> id; + unsafe fn URLByAppendingPathComponent_(self, path_component: id /* (NSString) */) -> id; + unsafe fn URLByAppendingPathComponent_isDirectory_(self, path_component: id /* (NSString) */, is_dir: BOOL) -> id; + unsafe fn URLByAppendingPathExtension_(self, extension: id /* (NSString) */) -> id; + unsafe fn URLByDeletingLastPathComponent(self) -> id; + unsafe fn URLByDeletingPathExtension(self) -> id; + unsafe fn URLByResolvingSymlinksInPath(self) -> id; + unsafe fn URLByStandardizingPath(self) -> id; + unsafe fn hasDirectoryPath(self) -> BOOL; + + unsafe fn bookmarkDataWithContentsOfURL_error_(_:Self, url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */; + unsafe fn bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(self, options: NSURLBookmarkCreationOptions, resource_value_for_keys: id /* (NSArray) */, relative_to_url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */; + // unsafe fn resourceValuesForKeys_fromBookmarkData_ + unsafe fn writeBookmarkData_toURL_options_error_(_:Self, data: id /* (NSData) */, to_url: id, options: NSURLBookmarkFileCreationOptions, error: id /* (NSError _Nullable) */) -> id; + unsafe fn startAccessingSecurityScopedResource(self) -> BOOL; + unsafe fn stopAccessingSecurityScopedResource(self); + unsafe fn NSURLBookmarkFileCreationOptions(self) -> NSURLBookmarkFileCreationOptions; + unsafe fn NSURLBookmarkCreationOptions(self) -> NSURLBookmarkCreationOptions; + unsafe fn NSURLBookmarkResolutionOptions(self) -> NSURLBookmarkResolutionOptions; + + // unsafe fn checkPromisedItemIsReachableAndReturnError_ + // unsafe fn getPromisedItemResourceValue_forKey_error_ + // unsafe fn promisedItemResourceValuesForKeys_error_ + + // unsafe fn URLFromPasteboard_ + // unsafe fn writeToPasteboard_ +} + +impl NSURL for id { + unsafe fn alloc(_: Self) -> id { + msg_send![class!(NSURL), alloc] + } + + unsafe fn URLWithString_(_:Self, string: id) -> id { + msg_send![class!(NSURL), URLWithString:string] + } + unsafe fn initWithString_(self, string: id) -> id { + msg_send![self, initWithString:string] + } + unsafe fn URLWithString_relativeToURL_(_:Self, string: id, url: id) -> id { + msg_send![class!(NSURL), URLWithString: string relativeToURL:url] + } + unsafe fn initWithString_relativeToURL_(self, string: id, url: id) -> id { + msg_send![self, initWithString:string relativeToURL:url] + } + unsafe fn fileURLWithPath_isDirectory_(_:Self, path: id, is_dir: BOOL) -> id { + msg_send![class!(NSURL), fileURLWithPath:path isDirectory:is_dir] + } + unsafe fn initFileURLWithPath_isDirectory_(self, path: id, is_dir: BOOL) -> id { + msg_send![self, initFileURLWithPath:path isDirectory:is_dir] + } + unsafe fn fileURLWithPath_relativeToURL_(_:Self, path: id, url: id) -> id { + msg_send![class!(NSURL), fileURLWithPath:path relativeToURL:url] + } + unsafe fn initFileURLWithPath_relativeToURL_(self, path: id, url: id) -> id { + msg_send![self, initFileURLWithPath:path relativeToURL:url] + } + unsafe fn fileURLWithPath_isDirectory_relativeToURL_(_:Self, path: id, is_dir: BOOL, url: id) -> id { + msg_send![class!(NSURL), fileURLWithPath:path isDirectory:is_dir relativeToURL:url] + } + unsafe fn initFileURLWithPath_isDirectory_relativeToURL_(self, path: id, is_dir: BOOL, url: id) -> id { + msg_send![self, initFileURLWithPath:path isDirectory:is_dir relativeToURL:url] + } + unsafe fn fileURLWithPath_(_:Self, path: id) -> id { + msg_send![class!(NSURL), fileURLWithPath:path] + } + unsafe fn initFileURLWithPath_(self, path: id) -> id { + msg_send![self, initFileURLWithPath:path] + } + unsafe fn fileURLWithPathComponents_(_:Self, path_components: id /* (NSArray*) */) -> id { + msg_send![class!(NSURL), fileURLWithPathComponents:path_components] + } + unsafe fn URLByResolvingAliasFileAtURL_options_error_(_:Self, url: id, options: NSURLBookmarkResolutionOptions, error: *mut id /* (NSError _Nullable) */) -> id { + msg_send![class!(NSURL), URLByResolvingAliasFileAtURL:url options:options error:error] + } + unsafe fn URLByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(_:Self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id { + msg_send![class!(NSURL), URLByResolvingBookmarkData:data options:options relativeToURL:relative_to_url bookmarkDataIsStale:is_stale error:error] + } + unsafe fn initByResolvingBookmarkData_options_relativeToURL_bookmarkDataIsStale_error_(self, data: id /* (NSData) */, options: NSURLBookmarkResolutionOptions, relative_to_url: id, is_stale: *mut BOOL, error: *mut id /* (NSError _Nullable) */) -> id { + msg_send![self, initByResolvingBookmarkData:data options:options relativeToURL:relative_to_url bookmarkDataIsStale:is_stale error:error] + } + // unsafe fn fileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ + // unsafe fn getFileSystemRepresentation_maxLength_ + // unsafe fn initFileURLWithFileSystemRepresentation_isDirectory_relativeToURL_ + unsafe fn absoluteURLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id { + msg_send![class!(NSURL), absoluteURLWithDataRepresentation:data relativeToURL:url] + } + unsafe fn initAbsoluteURLWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id { + msg_send![self, initAbsoluteURLWithDataRepresentation:data relativeToURL:url] + } + unsafe fn URLWithDataRepresentation_relativeToURL_(_:Self, data: id /* (NSData) */, url: id) -> id { + msg_send![class!(NSURL), URLWithDataRepresentation:data relativeToURL:url] + } + unsafe fn initWithDataRepresentation_relativeToURL_(self, data: id /* (NSData) */, url: id) -> id { + msg_send![self, initWithDataRepresentation:data relativeToURL:url] + } + unsafe fn dataRepresentation(self) -> id /* (NSData) */ { + msg_send![self, dataRepresentation] + } + + unsafe fn isEqual_(self, id: id) -> BOOL { + msg_send![self, isEqual:id] + } + + unsafe fn checkResourceIsReachableAndReturnError_(self, error: id /* (NSError _Nullable) */) -> BOOL { + msg_send![self, checkResourceIsReachableAndReturnError:error] + } + unsafe fn isFileReferenceURL(self) -> BOOL { + msg_send![self, isFileReferenceURL] + } + unsafe fn isFileURL(self) -> BOOL { + msg_send![self, isFileURL] + } + + unsafe fn absoluteString(self) -> id /* (NSString) */ { + msg_send![self, absoluteString] + } + unsafe fn absoluteURL(self) -> id /* (NSURL) */ { + msg_send![self, absoluteURL] + } + unsafe fn baseURL(self) -> id /* (NSURL) */ { + msg_send![self, baseURL] + } + // unsafe fn fileSystemRepresentation + unsafe fn fragment(self) -> id /* (NSString) */ { + msg_send![self, fragment] + } + unsafe fn host(self) -> id /* (NSString) */ { + msg_send![self, host] + } + unsafe fn lastPathComponent(self) -> id /* (NSString) */ { + msg_send![self, lastPathComponent] + } + unsafe fn parameterString(self) -> id /* (NSString) */ { + msg_send![self, parameterString] + } + unsafe fn password(self) -> id /* (NSString) */ { + msg_send![self, password] + } + unsafe fn path(self) -> id /* (NSString) */ { + msg_send![self, path] + } + unsafe fn pathComponents(self) -> id /* (NSArray) */ { + msg_send![self, pathComponents] + } + unsafe fn pathExtension(self) -> id /* (NSString) */ { + msg_send![self, pathExtension] + } + unsafe fn port(self) -> id /* (NSNumber) */ { + msg_send![self, port] + } + unsafe fn query(self) -> id /* (NSString) */ { + msg_send![self, query] + } + unsafe fn relativePath(self) -> id /* (NSString) */ { + msg_send![self, relativePath] + } + unsafe fn relativeString(self) -> id /* (NSString) */ { + msg_send![self, relativeString] + } + unsafe fn resourceSpecifier(self) -> id /* (NSString) */ { + msg_send![self, resourceSpecifier] + } + unsafe fn scheme(self) -> id /* (NSString) */ { + msg_send![self, scheme] + } + unsafe fn standardizedURL(self) -> id /* (NSURL) */ { + msg_send![self, standardizedURL] + } + unsafe fn user(self) -> id /* (NSString) */ { + msg_send![self, user] + } + + // unsafe fn resourceValuesForKeys_error_ + // unsafe fn getResourceValue_forKey_error_ + // unsafe fn setResourceValue_forKey_error_ + // unsafe fn setResourceValues_error_ + // unsafe fn removeAllCachedResourceValues + // unsafe fn removeCachedResourceValueForKey_ + // unsafe fn setTemporaryResourceValue_forKey_ + unsafe fn NSURLResourceKey(self) -> id /* (NSString) */ { + msg_send![self, NSURLResourceKey] + } + + unsafe fn filePathURL(self) -> id { + msg_send![self, filePathURL] + } + unsafe fn fileReferenceURL(self) -> id { + msg_send![self, fileReferenceURL] + } + unsafe fn URLByAppendingPathComponent_(self, path_component: id /* (NSString) */) -> id { + msg_send![self, URLByAppendingPathComponent:path_component] + } + unsafe fn URLByAppendingPathComponent_isDirectory_(self, path_component: id /* (NSString) */, is_dir: BOOL) -> id { + msg_send![self, URLByAppendingPathComponent:path_component isDirectory:is_dir] + } + unsafe fn URLByAppendingPathExtension_(self, extension: id /* (NSString) */) -> id { + msg_send![self, URLByAppendingPathExtension:extension] + } + unsafe fn URLByDeletingLastPathComponent(self) -> id { + msg_send![self, URLByDeletingLastPathComponent] + } + unsafe fn URLByDeletingPathExtension(self) -> id { + msg_send![self, URLByDeletingPathExtension] + } + unsafe fn URLByResolvingSymlinksInPath(self) -> id { + msg_send![self, URLByResolvingSymlinksInPath] + } + unsafe fn URLByStandardizingPath(self) -> id { + msg_send![self, URLByStandardizingPath] + } + unsafe fn hasDirectoryPath(self) -> BOOL { + msg_send![self, hasDirectoryPath] + } + + unsafe fn bookmarkDataWithContentsOfURL_error_(_:Self, url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */ { + msg_send![class!(NSURL), bookmarkDataWithContentsOfURL:url error:error] + } + unsafe fn bookmarkDataWithOptions_includingResourceValuesForKeys_relativeToURL_error_(self, options: NSURLBookmarkCreationOptions, resource_value_for_keys: id /* (NSArray) */, relative_to_url: id, error: id /* (NSError _Nullable) */) -> id /* (NSData) */ { + msg_send![self, bookmarkDataWithOptions:options includingResourceValuesForKeys:resource_value_for_keys relativeToURL:relative_to_url error:error] + } + // unsafe fn resourceValuesForKeys_fromBookmarkData_ + unsafe fn writeBookmarkData_toURL_options_error_(_:Self, data: id /* (NSData) */, to_url: id, options: NSURLBookmarkFileCreationOptions, error: id /* (NSError _Nullable) */) -> id { + msg_send![class!(NSURL), writeBookmarkData:data toURL:to_url options:options error:error] + } + unsafe fn startAccessingSecurityScopedResource(self) -> BOOL { + msg_send![self, startAccessingSecurityScopedResource] + } + unsafe fn stopAccessingSecurityScopedResource(self) { + msg_send![self, stopAccessingSecurityScopedResource] + } + unsafe fn NSURLBookmarkFileCreationOptions(self) -> NSURLBookmarkFileCreationOptions { + msg_send![self, NSURLBookmarkFileCreationOptions] + } + unsafe fn NSURLBookmarkCreationOptions(self) -> NSURLBookmarkCreationOptions { + msg_send![self, NSURLBookmarkCreationOptions] + } + unsafe fn NSURLBookmarkResolutionOptions(self) -> NSURLBookmarkResolutionOptions { + msg_send![self, NSURLBookmarkResolutionOptions] + } + + // unsafe fn checkPromisedItemIsReachableAndReturnError_ + // unsafe fn getPromisedItemResourceValue_forKey_error_ + // unsafe fn promisedItemResourceValuesForKeys_error_ + + // unsafe fn URLFromPasteboard_ + // unsafe fn writeToPasteboard_ +} + +pub trait NSBundle: Sized { + unsafe fn mainBundle() -> Self; + + unsafe fn loadNibNamed_owner_topLevelObjects_(self, + name: id /* NSString */, + owner: id, + topLevelObjects: *mut id /* NSArray */) -> BOOL; +} + +impl NSBundle for id { + unsafe fn mainBundle() -> id { + msg_send![class!(NSBundle), mainBundle] + } + + unsafe fn loadNibNamed_owner_topLevelObjects_(self, + name: id /* NSString */, + owner: id, + topLevelObjects: *mut id /* NSArray* */) -> BOOL { + msg_send![self, loadNibNamed:name + owner:owner + topLevelObjects:topLevelObjects] + } +} + +pub trait NSData: Sized { + unsafe fn data(_: Self) -> id { + msg_send![class!(NSData), data] + } + + unsafe fn dataWithBytes_length_(_: Self, bytes: *const c_void, length: NSUInteger) -> id { + msg_send![class!(NSData), dataWithBytes:bytes length:length] + } + + unsafe fn dataWithBytesNoCopy_length_(_: Self, bytes: *const c_void, length: NSUInteger) -> id { + msg_send![class!(NSData), dataWithBytesNoCopy:bytes length:length] + } + + unsafe fn dataWithBytesNoCopy_length_freeWhenDone_(_: Self, bytes: *const c_void, + length: NSUInteger, freeWhenDone: BOOL) -> id { + msg_send![class!(NSData), dataWithBytesNoCopy:bytes length:length freeWhenDone:freeWhenDone] + } + + unsafe fn dataWithContentsOfFile_(_: Self, path: id) -> id { + msg_send![class!(NSData), dataWithContentsOfFile:path] + } + + unsafe fn dataWithContentsOfFile_options_error_(_: Self, path: id, mask: NSDataReadingOptions, + errorPtr: *mut id) -> id { + msg_send![class!(NSData), dataWithContentsOfFile:path options:mask error:errorPtr] + } + + unsafe fn dataWithContentsOfURL_(_: Self, aURL: id) -> id { + msg_send![class!(NSData), dataWithContentsOfURL:aURL] + } + + unsafe fn dataWithContentsOfURL_options_error_(_: Self, aURL: id, mask: NSDataReadingOptions, + errorPtr: *mut id) -> id { + msg_send![class!(NSData), dataWithContentsOfURL:aURL options:mask error:errorPtr] + } + + unsafe fn dataWithData_(_: Self, aData: id) -> id { + msg_send![class!(NSData), dataWithData:aData] + } + + unsafe fn initWithBase64EncodedData_options_(self, base64Data: id, options: NSDataBase64DecodingOptions) + -> id; + unsafe fn initWithBase64EncodedString_options_(self, base64String: id, options: NSDataBase64DecodingOptions) + -> id; + unsafe fn initWithBytes_length_(self, bytes: *const c_void, length: NSUInteger) -> id; + unsafe fn initWithBytesNoCopy_length_(self, bytes: *const c_void, length: NSUInteger) -> id; + unsafe fn initWithBytesNoCopy_length_deallocator_(self, bytes: *const c_void, length: NSUInteger, + deallocator: *mut Block<(*const c_void, NSUInteger), ()>) + -> id; + unsafe fn initWithBytesNoCopy_length_freeWhenDone_(self, bytes: *const c_void, + length: NSUInteger, freeWhenDone: BOOL) -> id; + unsafe fn initWithContentsOfFile_(self, path: id) -> id; + unsafe fn initWithContentsOfFile_options_error(self, path: id, mask: NSDataReadingOptions, errorPtr: *mut id) + -> id; + unsafe fn initWithContentsOfURL_(self, aURL: id) -> id; + unsafe fn initWithContentsOfURL_options_error_(self, aURL: id, mask: NSDataReadingOptions, errorPtr: *mut id) + -> id; + unsafe fn initWithData_(self, data: id) -> id; + + unsafe fn bytes(self) -> *const c_void; + unsafe fn description(self) -> id; + unsafe fn enumerateByteRangesUsingBlock_(self, block: *mut Block<(*const c_void, NSRange, *mut BOOL), ()>); + unsafe fn getBytes_length_(self, buffer: *mut c_void, length: NSUInteger); + unsafe fn getBytes_range_(self, buffer: *mut c_void, range: NSRange); + unsafe fn subdataWithRange_(self, range: NSRange) -> id; + unsafe fn rangeOfData_options_range_(self, dataToFind: id, options: NSDataSearchOptions, searchRange: NSRange) + -> NSRange; + + unsafe fn base64EncodedDataWithOptions_(self, options: NSDataBase64EncodingOptions) -> id; + unsafe fn base64EncodedStringWithOptions_(self, options: NSDataBase64EncodingOptions) -> id; + + unsafe fn isEqualToData_(self, otherData: id) -> id; + unsafe fn length(self) -> NSUInteger; + + unsafe fn writeToFile_atomically_(self, path: id, atomically: BOOL) -> BOOL; + unsafe fn writeToFile_options_error_(self, path: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL; + unsafe fn writeToURL_atomically_(self, aURL: id, atomically: BOOL) -> BOOL; + unsafe fn writeToURL_options_error_(self, aURL: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL; +} + +impl NSData for id { + unsafe fn initWithBase64EncodedData_options_(self, base64Data: id, options: NSDataBase64DecodingOptions) + -> id { + msg_send![self, initWithBase64EncodedData:base64Data options:options] + } + + unsafe fn initWithBase64EncodedString_options_(self, base64String: id, options: NSDataBase64DecodingOptions) + -> id { + msg_send![self, initWithBase64EncodedString:base64String options:options] + } + + unsafe fn initWithBytes_length_(self, bytes: *const c_void, length: NSUInteger) -> id { + msg_send![self,initWithBytes:bytes length:length] + } + + unsafe fn initWithBytesNoCopy_length_(self, bytes: *const c_void, length: NSUInteger) -> id { + msg_send![self, initWithBytesNoCopy:bytes length:length] + } + + unsafe fn initWithBytesNoCopy_length_deallocator_(self, bytes: *const c_void, length: NSUInteger, + deallocator: *mut Block<(*const c_void, NSUInteger), ()>) + -> id { + msg_send![self, initWithBytesNoCopy:bytes length:length deallocator:deallocator] + } + + unsafe fn initWithBytesNoCopy_length_freeWhenDone_(self, bytes: *const c_void, + length: NSUInteger, freeWhenDone: BOOL) -> id { + msg_send![self, initWithBytesNoCopy:bytes length:length freeWhenDone:freeWhenDone] + } + + unsafe fn initWithContentsOfFile_(self, path: id) -> id { + msg_send![self, initWithContentsOfFile:path] + } + + unsafe fn initWithContentsOfFile_options_error(self, path: id, mask: NSDataReadingOptions, errorPtr: *mut id) + -> id { + msg_send![self, initWithContentsOfFile:path options:mask error:errorPtr] + } + + unsafe fn initWithContentsOfURL_(self, aURL: id) -> id { + msg_send![self, initWithContentsOfURL:aURL] + } + + unsafe fn initWithContentsOfURL_options_error_(self, aURL: id, mask: NSDataReadingOptions, errorPtr: *mut id) + -> id { + msg_send![self, initWithContentsOfURL:aURL options:mask error:errorPtr] + } + + unsafe fn initWithData_(self, data: id) -> id { + msg_send![self, initWithData:data] + } + + unsafe fn bytes(self) -> *const c_void { + msg_send![self, bytes] + } + + unsafe fn description(self) -> id { + msg_send![self, description] + } + + unsafe fn enumerateByteRangesUsingBlock_(self, block: *mut Block<(*const c_void, NSRange, *mut BOOL), ()>) { + msg_send![self, enumerateByteRangesUsingBlock:block] + } + + unsafe fn getBytes_length_(self, buffer: *mut c_void, length: NSUInteger) { + msg_send![self, getBytes:buffer length:length] + } + + unsafe fn getBytes_range_(self, buffer: *mut c_void, range: NSRange) { + msg_send![self, getBytes:buffer range:range] + } + + unsafe fn subdataWithRange_(self, range: NSRange) -> id { + msg_send![self, subdataWithRange:range] + } + + unsafe fn rangeOfData_options_range_(self, dataToFind: id, options: NSDataSearchOptions, searchRange: NSRange) + -> NSRange { + msg_send![self, rangeOfData:dataToFind options:options range:searchRange] + } + + unsafe fn base64EncodedDataWithOptions_(self, options: NSDataBase64EncodingOptions) -> id { + msg_send![self, base64EncodedDataWithOptions:options] + } + + unsafe fn base64EncodedStringWithOptions_(self, options: NSDataBase64EncodingOptions) -> id { + msg_send![self, base64EncodedStringWithOptions:options] + } + + unsafe fn isEqualToData_(self, otherData: id) -> id { + msg_send![self, isEqualToData:otherData] + } + + unsafe fn length(self) -> NSUInteger { + msg_send![self, length] + } + + unsafe fn writeToFile_atomically_(self, path: id, atomically: BOOL) -> BOOL { + msg_send![self, writeToFile:path atomically:atomically] + } + + unsafe fn writeToFile_options_error_(self, path: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL { + msg_send![self, writeToFile:path options:mask error:errorPtr] + } + + unsafe fn writeToURL_atomically_(self, aURL: id, atomically: BOOL) -> BOOL { + msg_send![self, writeToURL:aURL atomically:atomically] + } + + unsafe fn writeToURL_options_error_(self, aURL: id, mask: NSDataWritingOptions, errorPtr: *mut id) -> BOOL { + msg_send![self, writeToURL:aURL options:mask error:errorPtr] + } +} + +bitflags! { + pub struct NSDataReadingOptions: libc::c_ulonglong { + const NSDataReadingMappedIfSafe = 1 << 0; + const NSDataReadingUncached = 1 << 1; + const NSDataReadingMappedAlways = 1 << 3; + } +} + +bitflags! { + pub struct NSDataBase64EncodingOptions: libc::c_ulonglong { + const NSDataBase64Encoding64CharacterLineLength = 1 << 0; + const NSDataBase64Encoding76CharacterLineLength = 1 << 1; + const NSDataBase64EncodingEndLineWithCarriageReturn = 1 << 4; + const NSDataBase64EncodingEndLineWithLineFeed = 1 << 5; + } +} + +bitflags! { + pub struct NSDataBase64DecodingOptions: libc::c_ulonglong { + const NSDataBase64DecodingIgnoreUnknownCharacters = 1 << 0; + } +} + +bitflags! { + pub struct NSDataWritingOptions: libc::c_ulonglong { + const NSDataWritingAtomic = 1 << 0; + const NSDataWritingWithoutOverwriting = 1 << 1; + } +} + +bitflags! { + pub struct NSDataSearchOptions: libc::c_ulonglong { + const NSDataSearchBackwards = 1 << 0; + const NSDataSearchAnchored = 1 << 1; + } +} + +pub trait NSUserDefaults { + unsafe fn standardUserDefaults() -> Self; + + unsafe fn setBool_forKey_(self, value: BOOL, key: id); + unsafe fn bool_forKey_(self, key: id) -> BOOL; + + unsafe fn removeObject_forKey_(self, key: id); +} + +impl NSUserDefaults for id { + unsafe fn standardUserDefaults() -> id { + msg_send![class!(NSUserDefaults), standardUserDefaults] + } + + unsafe fn setBool_forKey_(self, value: BOOL, key: id) { + msg_send![self, setBool:value forKey:key] + } + + unsafe fn bool_forKey_(self, key: id) -> BOOL { + msg_send![self, boolForKey: key] + } + + unsafe fn removeObject_forKey_(self, key: id) { + msg_send![self, removeObjectForKey:key] + } +} diff --git a/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/lib.rs b/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/lib.rs new file mode 100644 index 0000000..6a23ccb --- /dev/null +++ b/third_party/cargo/vendor/cocoa-foundation-0.1.0/src/lib.rs @@ -0,0 +1,23 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_snake_case)] + +extern crate block; +#[macro_use] +extern crate bitflags; +extern crate core_foundation; +extern crate core_graphics_types; +extern crate foreign_types; +extern crate libc; +#[macro_use] +extern crate objc; + +pub mod base; +pub mod foundation; diff --git a/third_party/cargo/vendor/cocoa-foundation-0.1.0/tests/foundation.rs b/third_party/cargo/vendor/cocoa-foundation-0.1.0/tests/foundation.rs new file mode 100644 index 0000000..ab6401b --- /dev/null +++ b/third_party/cargo/vendor/cocoa-foundation-0.1.0/tests/foundation.rs @@ -0,0 +1,195 @@ +#[macro_use] +extern crate objc; +extern crate block; +extern crate cocoa_foundation; + +#[cfg(test)] +mod foundation { + mod nsstring { + use cocoa_foundation::foundation::NSString; + use cocoa_foundation::base::nil; + use std::slice; + use std::str; + + #[test] + fn test_utf8() { + let expected = "Iñtërnâtiônàlizætiøn"; + unsafe { + let built = NSString::alloc(nil).init_str(expected); + let bytes = built.UTF8String() as *const u8; + let objc_string = str::from_utf8(slice::from_raw_parts(bytes, built.len())) + .unwrap(); + assert_eq!(objc_string.len(), expected.len()); + assert_eq!(objc_string, expected); + } + } + + #[test] + fn test_string() { + let expected = "Hello World!"; + unsafe { + let built = NSString::alloc(nil).init_str(expected); + let bytes = built.UTF8String() as *const u8; + let objc_string = str::from_utf8(slice::from_raw_parts(bytes, built.len())) + .unwrap(); + assert_eq!(objc_string.len(), expected.len()); + assert_eq!(objc_string, expected); + } + } + + #[test] + fn test_length() { + let expected = "Hello!"; + unsafe { + let built = NSString::alloc(nil).init_str(expected); + assert_eq!(built.len(), expected.len()); + } + } + + #[test] + fn test_append_by_appending_string() { + let initial_str = "Iñtërnâtiônàlizætiøn"; + let to_append = "_more_strings"; + let expected = concat!("Iñtërnâtiônàlizætiøn", "_more_strings"); + unsafe { + let built = NSString::alloc(nil).init_str(initial_str); + let built_to_append = NSString::alloc(nil).init_str(to_append); + let append_string = built.stringByAppendingString_(built_to_append); + let bytes = append_string.UTF8String() as *const u8; + let objc_string = str::from_utf8(slice::from_raw_parts(bytes, append_string.len())) + .unwrap(); + assert_eq!(objc_string, expected); + } + } + } + + mod nsfastenumeration { + use std::str; + use std::slice; + use cocoa_foundation::foundation::{NSString, NSFastEnumeration}; + use cocoa_foundation::base::{id, nil}; + + #[test] + fn test_iter() { + unsafe { + let string = NSString::alloc(nil).init_str("this is a test string"); + let separator = NSString::alloc(nil).init_str(" "); + let components: id = msg_send![string, componentsSeparatedByString: separator]; + + let combined = components.iter() + .map(|s| { + let bytes = s.UTF8String() as *const u8; + str::from_utf8(slice::from_raw_parts(bytes, s.len())).unwrap() + }) + .fold(String::new(), |mut acc, s| { + acc.push_str(s); + acc + }); + + assert_eq!(combined, "thisisateststring"); + } + } + + #[test] + #[should_panic] + fn test_mutation() { + unsafe { + let string = NSString::alloc(nil).init_str("this is a test string"); + let separator = NSString::alloc(nil).init_str(" "); + let components: id = msg_send![string, componentsSeparatedByString: separator]; + let mut_components: id = msg_send![components, mutableCopy]; + let mut iter = mut_components.iter(); + iter.next(); + let () = msg_send![mut_components, removeObjectAtIndex:1]; + iter.next(); + } + } + } + + mod nsdictionary { + use block::ConcreteBlock; + use cocoa_foundation::foundation::{NSArray, NSComparisonResult, NSDictionary, NSFastEnumeration, + NSString}; + use cocoa_foundation::base::{id, nil}; + + #[test] + fn test_get() { + const KEY: &'static str = "The key"; + const VALUE: &'static str = "Some value"; + unsafe { + let key = NSString::alloc(nil).init_str(KEY); + let value = NSString::alloc(nil).init_str(VALUE); + let dict = NSDictionary::dictionaryWithObject_forKey_(nil, value, key); + + let retrieved_value = dict.objectForKey_(key); + assert!(retrieved_value.isEqualToString(VALUE)); + } + } + + #[test] + fn test_iter() { + let mkstr = |s| unsafe { NSString::alloc(nil).init_str(s) }; + let keys = vec!["a", "b", "c", "d", "e", "f"]; + let objects = vec!["1", "2", "3", "4", "5", "6"]; + unsafe { + use std::{slice, str}; + use std::cmp::{Ord, Ordering}; + + let keys_raw_vec = keys.clone().into_iter().map(&mkstr).collect::>(); + let objs_raw_vec = objects.clone().into_iter().map(&mkstr).collect::>(); + + let keys_array = NSArray::arrayWithObjects(nil, &keys_raw_vec); + let objs_array = NSArray::arrayWithObjects(nil, &objs_raw_vec); + + let dict = + NSDictionary::dictionaryWithObjects_forKeys_(nil, objs_array, keys_array); + + // NSDictionary does not store its contents in order of insertion, so ask for + // sorted iterators to ensure that each item is the same as its counterpart in + // the vector. + + fn compare_function(s0: &id, s1: &id) -> Ordering { + unsafe { + let (bytes0, len0) = (s0.UTF8String() as *const u8, s0.len()); + let (bytes1, len1) = (s1.UTF8String() as *const u8, s1.len()); + let (s0, s1) = (str::from_utf8(slice::from_raw_parts(bytes0, len0)).unwrap(), + str::from_utf8(slice::from_raw_parts(bytes1, len1)).unwrap()); + let (c0, c1) = (s0.chars().next().unwrap(), s1.chars().next().unwrap()); + c0.cmp(&c1) + } + } + + // First test cocoa sorting... + let mut comparator = ConcreteBlock::new(|s0: id, s1: id| { + match compare_function(&s0, &s1) { + Ordering::Less => NSComparisonResult::NSOrderedAscending, + Ordering::Equal => NSComparisonResult::NSOrderedSame, + Ordering::Greater => NSComparisonResult::NSOrderedDescending, + } + }); + + let associated_iter = keys.iter().zip(objects.iter()); + for (k_id, (k, v)) in dict.keysSortedByValueUsingComparator_(&mut *comparator) + .iter() + .zip(associated_iter) { + assert!(k_id.isEqualToString(k)); + let v_id = dict.objectForKey_(k_id); + assert!(v_id.isEqualToString(v)); + } + + // Then use rust sorting + let mut keys_arr = dict.allKeys().iter().collect::>(); + keys_arr.sort_by(compare_function); + for (k0, k1) in keys_arr.into_iter().zip(keys.iter()) { + assert!(k0.isEqualToString(k1)); + } + + let mut objects_arr = dict.allValues().iter().collect::>(); + objects_arr.sort_by(compare_function); + for (v0, v1) in objects_arr.into_iter().zip(objects.iter()) { + assert!(v0.isEqualToString(v1)); + } + } + } + } +} diff --git a/third_party/cargo/vendor/color_quant-1.0.1/.cargo-checksum.json b/third_party/cargo/vendor/color_quant-1.0.1/.cargo-checksum.json deleted file mode 100644 index 4cdcbe5..0000000 --- a/third_party/cargo/vendor/color_quant-1.0.1/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"688bd8abbac3aa77f7576eb16fb9d893d6ea46ae73815fce3e93289e0388db39","LICENSE":"592dc80f1a865d20d61a2006a2d29ce34a2bc28cd7e868ab300fdeed6da154ca","README.md":"f185944aa94e2457b094d9c3946d743d36e1381c6a8bb9beca07a7e21ce2137f","src/lib.rs":"49b5bde7cf83947e0fbdfcd403e0e8e7f1825b5be50c1d0523a7b798c886c4f7"},"package":"0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"} \ No newline at end of file diff --git a/third_party/cargo/vendor/color_quant-1.0.1/BUILD.bazel b/third_party/cargo/vendor/color_quant-1.0.1/BUILD.bazel deleted file mode 100644 index 1df8be2..0000000 --- a/third_party/cargo/vendor/color_quant-1.0.1/BUILD.bazel +++ /dev/null @@ -1,53 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT" -]) - -# Generated Targets - -rust_library( - name = "color_quant", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.0.1", - # buildifier: leave-alone - deps = [ - ], -) diff --git a/third_party/cargo/vendor/color_quant-1.0.1/Cargo.toml b/third_party/cargo/vendor/color_quant-1.0.1/Cargo.toml deleted file mode 100644 index 67fc5f8..0000000 --- a/third_party/cargo/vendor/color_quant-1.0.1/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "color_quant" -version = "1.0.1" -authors = ["nwin "] -description = "Color quantization library to reduce n colors to 256 colors." -readme = "README.md" -license = "MIT" -repository = "https://github.com/PistonDevelopers/color_quant.git" diff --git a/third_party/cargo/vendor/color_quant-1.0.1/README.md b/third_party/cargo/vendor/color_quant-1.0.1/README.md deleted file mode 100644 index eea6856..0000000 --- a/third_party/cargo/vendor/color_quant-1.0.1/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Color quantization library -This library provides a color quantizer based on the [NEUQUANT](http://members.ozemail.com.au/~dekker/NEUQUANT.HTML) -quantization algorithm by Anthony Dekker. - -### Usage - - let data = vec![0; 40]; - let nq = color_quant::NeuQuant::new(10, 256, &data); - let indixes: Vec = data.chunks(4).map(|pix| nq.index_of(pix) as u8).collect(); - let color_map = nq.color_map_rgba(); - diff --git a/third_party/cargo/vendor/color_quant-1.0.1/src/lib.rs b/third_party/cargo/vendor/color_quant-1.0.1/src/lib.rs deleted file mode 100644 index 96d4b69..0000000 --- a/third_party/cargo/vendor/color_quant-1.0.1/src/lib.rs +++ /dev/null @@ -1,440 +0,0 @@ -/* -NeuQuant Neural-Net Quantization Algorithm by Anthony Dekker, 1994. -See "Kohonen neural networks for optimal colour quantization" -in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. -for a discussion of the algorithm. -See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML - -Incorporated bugfixes and alpha channel handling from pngnq -http://pngnq.sourceforge.net - -Copyright (c) 2014 The Piston Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -NeuQuant Neural-Net Quantization Algorithm ------------------------------------------- - -Copyright (c) 1994 Anthony Dekker - -NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. -See "Kohonen neural networks for optimal colour quantization" -in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. -for a discussion of the algorithm. -See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML - -Any party obtaining a copy of these files from the author, directly or -indirectly, is granted, free of charge, a full and unrestricted irrevocable, -world-wide, paid up, royalty-free, nonexclusive right and license to deal -in this software and documentation files (the "Software"), including without -limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons who receive -copies from any such party to do so, with the only requirement being -that this copyright notice remain intact. - -*/ -//! # Color quantization library -//! This library provides a color quantizer based on the [NEUQUANT](http://members.ozemail.com.au/~dekker/NEUQUANT.HTML) -//! quantization algorithm by Anthony Dekker. -//! ### Usage -//! ``` -//! let data = vec![0; 40]; -//! let nq = color_quant::NeuQuant::new(10, 256, &data); -//! let indixes: Vec = data.chunks(4).map(|pix| nq.index_of(pix) as u8).collect(); -//! let color_map = nq.color_map_rgba(); -//! ``` -//! -use std::cmp::{ - max, - min -}; - -macro_rules! clamp( - ($x:expr) => (match $x { - x if x < 0 => 0, - x if x > 255 => 255, - x => x - }) -); - -const CHANNELS: usize = 4; - -const RADIUS_DEC: i32 = 30; // factor of 1/30 each cycle - -const ALPHA_BIASSHIFT: i32 = 10; // alpha starts at 1 -const INIT_ALPHA: i32 = 1 << ALPHA_BIASSHIFT; // biased by 10 bits - -const GAMMA: f64 = 1024.0; -const BETA: f64 = 1.0 / GAMMA; -const BETAGAMMA: f64 = BETA * GAMMA; - -// four primes near 500 - assume no image has a length so large -// that it is divisible by all four primes -const PRIMES: [usize; 4] = [499, 491, 478, 503]; - -#[derive(Clone, Copy)] -struct Quad { - r: T, - g: T, - b: T, - a: T, -} - -type Neuron = Quad; -type Color = Quad; - -/// Neural network based color quantizer. -pub struct NeuQuant { - network: Vec, - colormap: Vec, - netindex: Vec, - bias: Vec, // bias and freq arrays for learning - freq: Vec, - samplefac: i32, - netsize: usize, -} - -impl NeuQuant { - /// Creates a new neuronal network and trains it with the supplied data. - /// - /// Pixels are assumed to be in RGBA format. - /// `colors` should be $>=64$. `samplefac` determines the faction of - /// the sample that will be used to train the network. Its value must be in the - /// range $[1, 30]$. A value of $1$ thus produces the best result but is also - /// slowest. $10$ is a good compromise between speed and quality. - pub fn new(samplefac: i32, colors: usize, pixels: &[u8]) -> Self { - let netsize = colors; - let mut this = NeuQuant { - network: Vec::with_capacity(netsize), - colormap: Vec::with_capacity(netsize), - netindex: vec![0; 256], - bias: Vec::with_capacity(netsize), - freq: Vec::with_capacity(netsize), - samplefac: samplefac, - netsize: colors - }; - this.init(pixels); - this - } - - /// Initializes the neuronal network and trains it with the supplied data. - /// - /// This method gets called by `Self::new`. - pub fn init(&mut self, pixels: &[u8]) { - self.network.clear(); - self.colormap.clear(); - self.bias.clear(); - self.freq.clear(); - let freq = (self.netsize as f64).recip(); - for i in 0..self.netsize { - let tmp = (i as f64) * 256.0 / (self.netsize as f64); - // Sets alpha values at 0 for dark pixels. - let a = if i < 16 { i as f64 * 16.0 } else { 255.0 }; - self.network.push(Neuron { r: tmp, g: tmp, b: tmp, a: a}); - self.colormap.push(Color { r: 0, g: 0, b: 0, a: 255 }); - self.freq.push(freq); - self.bias.push(0.0); - } - self.learn(pixels); - self.build_colormap(); - self.inxbuild(); - } - - /// Maps the rgba-pixel in-place to the best-matching color in the color map. - #[inline(always)] - pub fn map_pixel(&self, pixel: &mut [u8]) { - assert!(pixel.len() == 4); - match (pixel[0], pixel[1], pixel[2], pixel[3]) { - (r, g, b, a) => { - let i = self.inxsearch(b, g, r, a); - pixel[0] = self.colormap[i].r as u8; - pixel[1] = self.colormap[i].g as u8; - pixel[2] = self.colormap[i].b as u8; - pixel[3] = self.colormap[i].a as u8; - } - } - } - - /// Finds the best-matching index in the color map. - /// - /// `pixel` is assumed to be in RGBA format. - #[inline(always)] - pub fn index_of(&self, pixel: &[u8]) -> usize { - assert!(pixel.len() == 4); - match (pixel[0], pixel[1], pixel[2], pixel[3]) { - (r, g, b, a) => { - self.inxsearch(b, g, r, a) - } - } - } - - /// Returns the RGBA color map calculated from the sample. - pub fn color_map_rgba(&self) -> Vec { - let mut map = Vec::with_capacity(self.netsize * 4); - for entry in &self.colormap { - map.push(entry.r as u8); - map.push(entry.g as u8); - map.push(entry.b as u8); - map.push(entry.a as u8); - } - map - } - - /// Returns the RGBA color map calculated from the sample. - pub fn color_map_rgb(&self) -> Vec { - let mut map = Vec::with_capacity(self.netsize * 3); - for entry in &self.colormap { - map.push(entry.r as u8); - map.push(entry.g as u8); - map.push(entry.b as u8); - } - map - } - - /// Move neuron i towards biased (a,b,g,r) by factor alpha - fn altersingle(&mut self, alpha: f64, i: i32, quad: Quad) { - let n = &mut self.network[i as usize]; - n.b -= alpha * (n.b - quad.b); - n.g -= alpha * (n.g - quad.g); - n.r -= alpha * (n.r - quad.r); - n.a -= alpha * (n.a - quad.a); - } - - /// Move neuron adjacent neurons towards biased (a,b,g,r) by factor alpha - fn alterneigh(&mut self, alpha: f64, rad: i32, i: i32, quad: Quad) { - let lo = max(i - rad, 0); - let hi = min(i + rad, self.netsize as i32); - let mut j = i + 1; - let mut k = i - 1; - let mut q = 0; - - while (j < hi) || (k > lo) { - let rad_sq = rad as f64 * rad as f64; - let alpha = (alpha * (rad_sq - q as f64 * q as f64)) / rad_sq; - q += 1; - if j < hi { - let p = &mut self.network[j as usize]; - p.b -= alpha * (p.b - quad.b); - p.g -= alpha * (p.g - quad.g); - p.r -= alpha * (p.r - quad.r); - p.a -= alpha * (p.a - quad.a); - j += 1; - } - if k > lo { - let p = &mut self.network[k as usize]; - p.b -= alpha * (p.b - quad.b); - p.g -= alpha * (p.g - quad.g); - p.r -= alpha * (p.r - quad.r); - p.a -= alpha * (p.a - quad.a); - k -= 1; - } - } - } - - /// Search for biased BGR values - /// finds closest neuron (min dist) and updates freq - /// finds best neuron (min dist-bias) and returns position - /// for frequently chosen neurons, freq[i] is high and bias[i] is negative - /// bias[i] = gamma*((1/self.netsize)-freq[i]) - fn contest (&mut self, b: f64, g: f64, r: f64, a: f64) -> i32 { - use std::f64; - - let mut bestd = f64::MAX; - let mut bestbiasd: f64 = bestd; - let mut bestpos = -1; - let mut bestbiaspos: i32 = bestpos; - - for i in 0..self.netsize { - let bestbiasd_biased = bestbiasd + self.bias[i]; - let mut dist; - let n = &self.network[i]; - dist = (n.b - b).abs(); - dist += (n.r - r).abs(); - if dist < bestd || dist < bestbiasd_biased { - dist += (n.g - g).abs(); - dist += (n.a - a).abs(); - if dist < bestd {bestd=dist; bestpos=i as i32;} - let biasdist = dist - self.bias [i]; - if biasdist < bestbiasd {bestbiasd=biasdist; bestbiaspos=i as i32;} - } - self.freq[i] -= BETA * self.freq[i]; - self.bias[i] += BETAGAMMA * self.freq[i]; - } - self.freq[bestpos as usize] += BETA; - self.bias[bestpos as usize] -= BETAGAMMA; - return bestbiaspos; - } - - /// Main learning loop - /// Note: the number of learning cycles is crucial and the parameters are not - /// optimized for net sizes < 26 or > 256. 1064 colors seems to work fine - fn learn(&mut self, pixels: &[u8]) { - let initrad: i32 = self.netsize as i32/8; // for 256 cols, radius starts at 32 - let radiusbiasshift: i32 = 6; - let radiusbias: i32 = 1 << radiusbiasshift; - let init_bias_radius: i32 = initrad*radiusbias; - let mut bias_radius = init_bias_radius; - let alphadec = 30 + ((self.samplefac-1)/3); - let lengthcount = pixels.len() / CHANNELS; - let samplepixels = lengthcount / self.samplefac as usize; - // learning cycles - let n_cycles = match self.netsize >> 1 { n if n <= 100 => 100, n => n}; - let delta = match samplepixels / n_cycles { 0 => 1, n => n }; - let mut alpha = INIT_ALPHA; - - let mut rad = bias_radius >> radiusbiasshift; - if rad <= 1 {rad = 0}; - - let mut pos = 0; - let step = *PRIMES.iter() - .find(|&&prime| lengthcount % prime != 0) - .unwrap_or(&PRIMES[3]); - - let mut i = 0; - while i < samplepixels { - let (r, g, b, a) = { - let p = &pixels[CHANNELS * pos..][..CHANNELS]; - (p[0] as f64, p[1] as f64, p[2] as f64, p[3] as f64) - }; - - let j = self.contest (b, g, r, a); - - let alpha_ = (1.0 * alpha as f64) / INIT_ALPHA as f64; - self.altersingle(alpha_, j, Quad { b: b, g: g, r: r, a: a }); - if rad > 0 { - self.alterneigh(alpha_, rad, j, Quad { b: b, g: g, r: r, a: a }) - }; - - pos += step; - while pos >= lengthcount { pos -= lengthcount }; - - i += 1; - if i%delta == 0 { - alpha -= alpha / alphadec; - bias_radius -= bias_radius / RADIUS_DEC; - rad = bias_radius >> radiusbiasshift; - if rad <= 1 {rad = 0}; - } - } - } - - /// initializes the color map - fn build_colormap(&mut self) { - for i in 0usize..self.netsize { - self.colormap[i].b = clamp!(self.network[i].b.round() as i32); - self.colormap[i].g = clamp!(self.network[i].g.round() as i32); - self.colormap[i].r = clamp!(self.network[i].r.round() as i32); - self.colormap[i].a = clamp!(self.network[i].a.round() as i32); - } - } - - /// Insertion sort of network and building of netindex[0..255] - fn inxbuild(&mut self) { - let mut previouscol = 0; - let mut startpos = 0; - - for i in 0..self.netsize { - let mut p = self.colormap[i]; - let mut q; - let mut smallpos = i; - let mut smallval = p.g as usize; // index on g - // find smallest in i..netsize-1 - for j in (i + 1)..self.netsize { - q = self.colormap[j]; - if (q.g as usize) < smallval { // index on g - smallpos = j; - smallval = q.g as usize; // index on g - } - } - q = self.colormap[smallpos]; - // swap p (i) and q (smallpos) entries - if i != smallpos { - let mut j; - j = q; q = p; p = j; - self.colormap[i] = p; - self.colormap[smallpos] = q; - } - // smallval entry is now in position i - if smallval != previouscol { - self.netindex[previouscol] = (startpos + i)>>1; - for j in (previouscol + 1)..smallval { - self.netindex[j] = i - } - previouscol = smallval; - startpos = i; - } - } - let max_netpos = self.netsize - 1; - self.netindex[previouscol] = (startpos + max_netpos)>>1; - for j in (previouscol + 1)..256 { self.netindex[j] = max_netpos }; // really 256 - } - - /// Search for best matching color - fn inxsearch(&self, b: u8, g: u8, r: u8, a: u8) -> usize { - let mut bestd = 1 << 30; // ~ 1_000_000 - let mut best = 0; - // start at netindex[g] and work outwards - let mut i = self.netindex[g as usize]; - let mut j = if i > 0 { i - 1 } else { 0 }; - - while (i < self.netsize) || (j > 0) { - if i < self.netsize { - let p = self.colormap[i]; - let mut e = p.g - g as i32; - let mut dist = e*e; // inx key - if dist >= bestd { break } - else { - e = p.b - b as i32; - dist += e*e; - if dist < bestd { - e = p.r - r as i32; - dist += e*e; - if dist < bestd { - e = p.a - a as i32; - dist += e*e; - if dist < bestd { bestd = dist; best = i;} - } - } - i += 1; - } - } - if j > 0 { - let p = self.colormap[j]; - let mut e = p.g - g as i32; - let mut dist = e*e; // inx key - if dist >= bestd { break } - else { - e = p.b - b as i32; - dist += e*e; - if dist < bestd { - e = p.r - r as i32; - dist += e*e; - if dist < bestd { - e = p.a - a as i32; - dist += e*e; - if dist < bestd { bestd = dist; best = j; } - } - } - j -= 1; - } - } - } - best - } -} \ No newline at end of file diff --git a/third_party/cargo/vendor/color_quant-1.1.0/.cargo-checksum.json b/third_party/cargo/vendor/color_quant-1.1.0/.cargo-checksum.json new file mode 100644 index 0000000..ea192c1 --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"0647ef6e3629446892fb530dc6f49977a3a81c4d943d0028b697ffa0d98565ad","Cargo.toml":"4ec438714084877d63c79e99191599a3694839c74842f81ca69de836a5889c75","LICENSE":"592dc80f1a865d20d61a2006a2d29ce34a2bc28cd7e868ab300fdeed6da154ca","README.md":"af03438f3b349f8e32ae2cf77c026948bd6493e7631ddd908ee0d225385c7894","src/lib.rs":"17a7ed7a6c994b475976558f3492c8890d089c1ee19f4ea3cd246c28145c895a","src/math.rs":"1fef0855d7d7defb8af69a033a2ce7e5f64367f48ba673cb4ce8e85e2006a124"},"package":"3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"} \ No newline at end of file diff --git a/third_party/cargo/vendor/color_quant-1.1.0/BUILD.bazel b/third_party/cargo/vendor/color_quant-1.1.0/BUILD.bazel new file mode 100644 index 0000000..82a20bb --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/BUILD.bazel @@ -0,0 +1,53 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT" +]) + +# Generated Targets + +rust_library( + name = "color_quant", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.1.0", + # buildifier: leave-alone + deps = [ + ], +) diff --git a/third_party/cargo/vendor/color_quant-1.1.0/CHANGELOG.md b/third_party/cargo/vendor/color_quant-1.1.0/CHANGELOG.md new file mode 100644 index 0000000..5609cf5 --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/CHANGELOG.md @@ -0,0 +1,7 @@ +## 1.1.0 + +- Unify with `image::math::nq` as per https://github.com/image-rs/image/issues/1338 (https://github.com/image-rs/color_quant/pull/10) + - A new method `lookup` from `image::math::nq` is added + - More references in docs + - Some style improvements and better names for functions borrowed from `image::math::nq` +- Replace the internal `clamp!` macro with the `clamp` function (https://github.com/image-rs/color_quant/pull/8) diff --git a/third_party/cargo/vendor/color_quant-1.1.0/Cargo.toml b/third_party/cargo/vendor/color_quant-1.1.0/Cargo.toml new file mode 100644 index 0000000..3bd3f2d --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/Cargo.toml @@ -0,0 +1,20 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "color_quant" +version = "1.1.0" +authors = ["nwin "] +description = "Color quantization library to reduce n colors to 256 colors." +readme = "README.md" +license = "MIT" +repository = "https://github.com/image-rs/color_quant.git" diff --git a/third_party/cargo/vendor/color_quant-1.0.1/LICENSE b/third_party/cargo/vendor/color_quant-1.1.0/LICENSE similarity index 100% rename from third_party/cargo/vendor/color_quant-1.0.1/LICENSE rename to third_party/cargo/vendor/color_quant-1.1.0/LICENSE diff --git a/third_party/cargo/vendor/color_quant-1.1.0/README.md b/third_party/cargo/vendor/color_quant-1.1.0/README.md new file mode 100644 index 0000000..0644ad6 --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/README.md @@ -0,0 +1,11 @@ +# Color quantization library +This library provides a color quantizer based on the [NEUQUANT](https://scientificgems.wordpress.com/stuff/neuquant-fast-high-quality-image-quantization/) +quantization algorithm by Anthony Dekker. + +### Usage + + let data = vec![0; 40]; + let nq = color_quant::NeuQuant::new(10, 256, &data); + let indixes: Vec = data.chunks(4).map(|pix| nq.index_of(pix) as u8).collect(); + let color_map = nq.color_map_rgba(); + diff --git a/third_party/cargo/vendor/color_quant-1.1.0/src/lib.rs b/third_party/cargo/vendor/color_quant-1.1.0/src/lib.rs new file mode 100644 index 0000000..afd0d93 --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/src/lib.rs @@ -0,0 +1,480 @@ +/* +NeuQuant Neural-Net Quantization Algorithm by Anthony Dekker, 1994. +See "Kohonen neural networks for optimal colour quantization" +in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. +for a discussion of the algorithm. +See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML + +Incorporated bugfixes and alpha channel handling from pngnq +http://pngnq.sourceforge.net + +Copyright (c) 2014 The Piston Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +NeuQuant Neural-Net Quantization Algorithm +------------------------------------------ + +Copyright (c) 1994 Anthony Dekker + +NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. +See "Kohonen neural networks for optimal colour quantization" +in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367. +for a discussion of the algorithm. +See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML + +Any party obtaining a copy of these files from the author, directly or +indirectly, is granted, free of charge, a full and unrestricted irrevocable, +world-wide, paid up, royalty-free, nonexclusive right and license to deal +in this software and documentation files (the "Software"), including without +limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons who receive +copies from any such party to do so, with the only requirement being +that this copyright notice remain intact. + +*/ + +//! # Color quantization library +//! +//! This library provides a color quantizer based on the [NEUQUANT](http://members.ozemail.com.au/~dekker/NEUQUANT.HTML) +//! +//! Original literature: Dekker, A. H. (1994). Kohonen neural networks for +//! optimal colour quantization. *Network: Computation in Neural Systems*, 5(3), 351-367. +//! [doi: 10.1088/0954-898X_5_3_003](https://doi.org/10.1088/0954-898X_5_3_003) +//! +//! See also +//! +//! ## Usage +//! +//! ``` +//! let data = vec![0; 40]; +//! let nq = color_quant::NeuQuant::new(10, 256, &data); +//! let indixes: Vec = data.chunks(4).map(|pix| nq.index_of(pix) as u8).collect(); +//! let color_map = nq.color_map_rgba(); +//! ``` + +mod math; +use crate::math::clamp; + +use std::cmp::{max, min}; + +const CHANNELS: usize = 4; + +const RADIUS_DEC: i32 = 30; // factor of 1/30 each cycle + +const ALPHA_BIASSHIFT: i32 = 10; // alpha starts at 1 +const INIT_ALPHA: i32 = 1 << ALPHA_BIASSHIFT; // biased by 10 bits + +const GAMMA: f64 = 1024.0; +const BETA: f64 = 1.0 / GAMMA; +const BETAGAMMA: f64 = BETA * GAMMA; + +// four primes near 500 - assume no image has a length so large +// that it is divisible by all four primes +const PRIMES: [usize; 4] = [499, 491, 478, 503]; + +#[derive(Clone, Copy)] +struct Quad { + r: T, + g: T, + b: T, + a: T, +} + +type Neuron = Quad; +type Color = Quad; + +pub struct NeuQuant { + network: Vec, + colormap: Vec, + netindex: Vec, + bias: Vec, // bias and freq arrays for learning + freq: Vec, + samplefac: i32, + netsize: usize, +} + +impl NeuQuant { + /// Creates a new neuronal network and trains it with the supplied data. + /// + /// Pixels are assumed to be in RGBA format. + /// `colors` should be $>=64$. `samplefac` determines the faction of + /// the sample that will be used to train the network. Its value must be in the + /// range $[1, 30]$. A value of $1$ thus produces the best result but is also + /// slowest. $10$ is a good compromise between speed and quality. + pub fn new(samplefac: i32, colors: usize, pixels: &[u8]) -> Self { + let netsize = colors; + let mut this = NeuQuant { + network: Vec::with_capacity(netsize), + colormap: Vec::with_capacity(netsize), + netindex: vec![0; 256], + bias: Vec::with_capacity(netsize), + freq: Vec::with_capacity(netsize), + samplefac: samplefac, + netsize: colors, + }; + this.init(pixels); + this + } + + /// Initializes the neuronal network and trains it with the supplied data. + /// + /// This method gets called by `Self::new`. + pub fn init(&mut self, pixels: &[u8]) { + self.network.clear(); + self.colormap.clear(); + self.bias.clear(); + self.freq.clear(); + let freq = (self.netsize as f64).recip(); + for i in 0..self.netsize { + let tmp = (i as f64) * 256.0 / (self.netsize as f64); + // Sets alpha values at 0 for dark pixels. + let a = if i < 16 { i as f64 * 16.0 } else { 255.0 }; + self.network.push(Neuron { + r: tmp, + g: tmp, + b: tmp, + a: a, + }); + self.colormap.push(Color { + r: 0, + g: 0, + b: 0, + a: 255, + }); + self.freq.push(freq); + self.bias.push(0.0); + } + self.learn(pixels); + self.build_colormap(); + self.build_netindex(); + } + + /// Maps the rgba-pixel in-place to the best-matching color in the color map. + #[inline(always)] + pub fn map_pixel(&self, pixel: &mut [u8]) { + assert!(pixel.len() == 4); + let (r, g, b, a) = (pixel[0], pixel[1], pixel[2], pixel[3]); + let i = self.search_netindex(b, g, r, a); + pixel[0] = self.colormap[i].r as u8; + pixel[1] = self.colormap[i].g as u8; + pixel[2] = self.colormap[i].b as u8; + pixel[3] = self.colormap[i].a as u8; + } + + /// Finds the best-matching index in the color map. + /// + /// `pixel` is assumed to be in RGBA format. + #[inline(always)] + pub fn index_of(&self, pixel: &[u8]) -> usize { + assert!(pixel.len() == 4); + let (r, g, b, a) = (pixel[0], pixel[1], pixel[2], pixel[3]); + self.search_netindex(b, g, r, a) + } + + /// Lookup pixel values for color at `idx` in the colormap. + pub fn lookup(&self, idx: usize) -> Option<[u8; 4]> { + self.colormap + .get(idx) + .map(|p| [p.r as u8, p.g as u8, p.b as u8, p.a as u8]) + } + + /// Returns the RGBA color map calculated from the sample. + pub fn color_map_rgba(&self) -> Vec { + let mut map = Vec::with_capacity(self.netsize * 4); + for entry in &self.colormap { + map.push(entry.r as u8); + map.push(entry.g as u8); + map.push(entry.b as u8); + map.push(entry.a as u8); + } + map + } + + /// Returns the RGBA color map calculated from the sample. + pub fn color_map_rgb(&self) -> Vec { + let mut map = Vec::with_capacity(self.netsize * 3); + for entry in &self.colormap { + map.push(entry.r as u8); + map.push(entry.g as u8); + map.push(entry.b as u8); + } + map + } + + /// Move neuron i towards biased (a,b,g,r) by factor alpha + fn salter_single(&mut self, alpha: f64, i: i32, quad: Quad) { + let n = &mut self.network[i as usize]; + n.b -= alpha * (n.b - quad.b); + n.g -= alpha * (n.g - quad.g); + n.r -= alpha * (n.r - quad.r); + n.a -= alpha * (n.a - quad.a); + } + + /// Move neuron adjacent neurons towards biased (a,b,g,r) by factor alpha + fn alter_neighbour(&mut self, alpha: f64, rad: i32, i: i32, quad: Quad) { + let lo = max(i - rad, 0); + let hi = min(i + rad, self.netsize as i32); + let mut j = i + 1; + let mut k = i - 1; + let mut q = 0; + + while (j < hi) || (k > lo) { + let rad_sq = rad as f64 * rad as f64; + let alpha = (alpha * (rad_sq - q as f64 * q as f64)) / rad_sq; + q += 1; + if j < hi { + let p = &mut self.network[j as usize]; + p.b -= alpha * (p.b - quad.b); + p.g -= alpha * (p.g - quad.g); + p.r -= alpha * (p.r - quad.r); + p.a -= alpha * (p.a - quad.a); + j += 1; + } + if k > lo { + let p = &mut self.network[k as usize]; + p.b -= alpha * (p.b - quad.b); + p.g -= alpha * (p.g - quad.g); + p.r -= alpha * (p.r - quad.r); + p.a -= alpha * (p.a - quad.a); + k -= 1; + } + } + } + + /// Search for biased BGR values + /// finds closest neuron (min dist) and updates freq + /// finds best neuron (min dist-bias) and returns position + /// for frequently chosen neurons, freq[i] is high and bias[i] is negative + /// bias[i] = gamma*((1/self.netsize)-freq[i]) + fn contest(&mut self, b: f64, g: f64, r: f64, a: f64) -> i32 { + use std::f64; + + let mut bestd = f64::MAX; + let mut bestbiasd: f64 = bestd; + let mut bestpos = -1; + let mut bestbiaspos: i32 = bestpos; + + for i in 0..self.netsize { + let bestbiasd_biased = bestbiasd + self.bias[i]; + let mut dist; + let n = &self.network[i]; + dist = (n.b - b).abs(); + dist += (n.r - r).abs(); + if dist < bestd || dist < bestbiasd_biased { + dist += (n.g - g).abs(); + dist += (n.a - a).abs(); + if dist < bestd { + bestd = dist; + bestpos = i as i32; + } + let biasdist = dist - self.bias[i]; + if biasdist < bestbiasd { + bestbiasd = biasdist; + bestbiaspos = i as i32; + } + } + self.freq[i] -= BETA * self.freq[i]; + self.bias[i] += BETAGAMMA * self.freq[i]; + } + self.freq[bestpos as usize] += BETA; + self.bias[bestpos as usize] -= BETAGAMMA; + return bestbiaspos; + } + + /// Main learning loop + /// Note: the number of learning cycles is crucial and the parameters are not + /// optimized for net sizes < 26 or > 256. 1064 colors seems to work fine + fn learn(&mut self, pixels: &[u8]) { + let initrad: i32 = self.netsize as i32 / 8; // for 256 cols, radius starts at 32 + let radiusbiasshift: i32 = 6; + let radiusbias: i32 = 1 << radiusbiasshift; + let init_bias_radius: i32 = initrad * radiusbias; + let mut bias_radius = init_bias_radius; + let alphadec = 30 + ((self.samplefac - 1) / 3); + let lengthcount = pixels.len() / CHANNELS; + let samplepixels = lengthcount / self.samplefac as usize; + // learning cycles + let n_cycles = match self.netsize >> 1 { + n if n <= 100 => 100, + n => n, + }; + let delta = match samplepixels / n_cycles { + 0 => 1, + n => n, + }; + let mut alpha = INIT_ALPHA; + + let mut rad = bias_radius >> radiusbiasshift; + if rad <= 1 { + rad = 0 + }; + + let mut pos = 0; + let step = *PRIMES + .iter() + .find(|&&prime| lengthcount % prime != 0) + .unwrap_or(&PRIMES[3]); + + let mut i = 0; + while i < samplepixels { + let (r, g, b, a) = { + let p = &pixels[CHANNELS * pos..][..CHANNELS]; + (p[0] as f64, p[1] as f64, p[2] as f64, p[3] as f64) + }; + + let j = self.contest(b, g, r, a); + + let alpha_ = (1.0 * alpha as f64) / INIT_ALPHA as f64; + self.salter_single(alpha_, j, Quad { b, g, r, a }); + if rad > 0 { + self.alter_neighbour(alpha_, rad, j, Quad { b, g, r, a }) + }; + + pos += step; + while pos >= lengthcount { + pos -= lengthcount + } + + i += 1; + if i % delta == 0 { + alpha -= alpha / alphadec; + bias_radius -= bias_radius / RADIUS_DEC; + rad = bias_radius >> radiusbiasshift; + if rad <= 1 { + rad = 0 + }; + } + } + } + + /// initializes the color map + fn build_colormap(&mut self) { + for i in 0usize..self.netsize { + self.colormap[i].b = clamp(self.network[i].b.round() as i32); + self.colormap[i].g = clamp(self.network[i].g.round() as i32); + self.colormap[i].r = clamp(self.network[i].r.round() as i32); + self.colormap[i].a = clamp(self.network[i].a.round() as i32); + } + } + + /// Insertion sort of network and building of netindex[0..255] + fn build_netindex(&mut self) { + let mut previouscol = 0; + let mut startpos = 0; + + for i in 0..self.netsize { + let mut p = self.colormap[i]; + let mut q; + let mut smallpos = i; + let mut smallval = p.g as usize; // index on g + // find smallest in i..netsize-1 + for j in (i + 1)..self.netsize { + q = self.colormap[j]; + if (q.g as usize) < smallval { + // index on g + smallpos = j; + smallval = q.g as usize; // index on g + } + } + q = self.colormap[smallpos]; + // swap p (i) and q (smallpos) entries + if i != smallpos { + ::std::mem::swap(&mut p, &mut q); + self.colormap[i] = p; + self.colormap[smallpos] = q; + } + // smallval entry is now in position i + if smallval != previouscol { + self.netindex[previouscol] = (startpos + i) >> 1; + for j in (previouscol + 1)..smallval { + self.netindex[j] = i + } + previouscol = smallval; + startpos = i; + } + } + let max_netpos = self.netsize - 1; + self.netindex[previouscol] = (startpos + max_netpos) >> 1; + for j in (previouscol + 1)..256 { + self.netindex[j] = max_netpos + } // really 256 + } + + /// Search for best matching color + fn search_netindex(&self, b: u8, g: u8, r: u8, a: u8) -> usize { + let mut bestd = 1 << 30; // ~ 1_000_000 + let mut best = 0; + // start at netindex[g] and work outwards + let mut i = self.netindex[g as usize]; + let mut j = if i > 0 { i - 1 } else { 0 }; + + while (i < self.netsize) || (j > 0) { + if i < self.netsize { + let p = self.colormap[i]; + let mut e = p.g - g as i32; + let mut dist = e * e; // inx key + if dist >= bestd { + break; + } else { + e = p.b - b as i32; + dist += e * e; + if dist < bestd { + e = p.r - r as i32; + dist += e * e; + if dist < bestd { + e = p.a - a as i32; + dist += e * e; + if dist < bestd { + bestd = dist; + best = i; + } + } + } + i += 1; + } + } + if j > 0 { + let p = self.colormap[j]; + let mut e = p.g - g as i32; + let mut dist = e * e; // inx key + if dist >= bestd { + break; + } else { + e = p.b - b as i32; + dist += e * e; + if dist < bestd { + e = p.r - r as i32; + dist += e * e; + if dist < bestd { + e = p.a - a as i32; + dist += e * e; + if dist < bestd { + bestd = dist; + best = j; + } + } + } + j -= 1; + } + } + } + best + } +} diff --git a/third_party/cargo/vendor/color_quant-1.1.0/src/math.rs b/third_party/cargo/vendor/color_quant-1.1.0/src/math.rs new file mode 100644 index 0000000..369c2ad --- /dev/null +++ b/third_party/cargo/vendor/color_quant-1.1.0/src/math.rs @@ -0,0 +1,10 @@ +#[inline] +pub(crate) fn clamp(a: i32) -> i32 { + if a < 0 { + 0 + } else if a > 255 { + 255 + } else { + a + } +} diff --git a/third_party/cargo/vendor/const_fn-0.4.5/.cargo-checksum.json b/third_party/cargo/vendor/const_fn-0.4.5/.cargo-checksum.json new file mode 100644 index 0000000..1891422 --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"3d4c8910c720a6467a5576a3ed910d852e3595b0a55a5e412514eefc481ec8d9","Cargo.toml":"9163a47eff7b4bd7d6ed96159d3b8b8452eb39aeb0b8e694309a99e47ddc99a7","LICENSE-APACHE":"0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"e2c098d1b809f792484ca7e4ff21a1992ae83693683ba39d4a0e34ba1be2760f","build.rs":"0095fffab24644ea5b04a6132b0ccb53762435cc637092e6d4c471c4cc66f60b","src/ast.rs":"4d4a1ddb8deefa31c3e798ffe9cb32752f9b5418c61a8e45be32ca0d5f9b63f3","src/error.rs":"9bc6f12801616dc1750346bf4228d1b172bee88777e9c8cb841dd9348fecbcf3","src/iter.rs":"4eccd018075a4f4839adef2e2cf05198780b9b60d6fbfa8188522c2ad8e82cb5","src/lib.rs":"3ad19d38445a06934b60abe94611c77145c0dbcdc28630abb9a5c27c6b6f998f","src/to_tokens.rs":"5e831889f220c5abaf0403e56b485fbbbb1c4516023e82934f69a230d76694bf","src/utils.rs":"b73f44e9260d32d71aa2712b242f8c451317f62ee1523595fca19878ac07dcd4"},"package":"28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"} \ No newline at end of file diff --git a/third_party/cargo/vendor/const_fn-0.4.5/BUILD.bazel b/third_party/cargo/vendor/const_fn-0.4.5/BUILD.bazel new file mode 100644 index 0000000..de1232c --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/BUILD.bazel @@ -0,0 +1,55 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # Apache-2.0 from expression "Apache-2.0 OR MIT" +]) + +# Generated Targets + +# Unsupported target "build-script-build" with type "custom-build" omitted + +rust_library( + name = "const_fn", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "proc-macro", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.4.5", + # buildifier: leave-alone + deps = [ + ], +) diff --git a/third_party/cargo/vendor/const_fn-0.4.5/CHANGELOG.md b/third_party/cargo/vendor/const_fn-0.4.5/CHANGELOG.md new file mode 100644 index 0000000..b46403a --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/CHANGELOG.md @@ -0,0 +1,149 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +This project adheres to [Semantic Versioning](https://semver.org). + + + +## [Unreleased] + +## [0.4.5] - 2021-01-05 + +- Exclude unneeded files from crates.io. + +## [0.4.4] - 2020-11-02 + +- [Accept `const_fn` attribute with no arguments and functions without `const` keyword.](https://github.com/taiki-e/const_fn/pull/34) + This allows `const_fn` to be used as an optional dependency. + + ```rust + #[cfg_attr(feature = "...", const_fn::const_fn)] + pub fn func() { + /* ... */ + } + ``` + +## [0.4.3] - 2020-11-02 + +- [`const_fn` no longer fails to compile if unable to determine rustc version. Instead, it now displays a warning.](https://github.com/taiki-e/const_fn/pull/31) + +- [`const_fn` no longer relies on debug print format.](https://github.com/taiki-e/const_fn/pull/30) + +## [0.4.2] - 2020-08-31 + +- [Improve error messages when failed to parse version information.](https://github.com/taiki-e/const_fn/pull/26) + +- [Fix compile failure with cargo installed by yum.](https://github.com/taiki-e/const_fn/pull/26) + +## [0.4.1] - 2020-08-25 + +- [Fix compile failure with non-cargo build systems.](https://github.com/taiki-e/const_fn/pull/23) + +## [0.4.0] - 2020-08-25 + +- [Add support for version-based code generation.](https://github.com/taiki-e/const_fn/pull/17) The following conditions are available: + + ```rust + use const_fn::const_fn; + + // function is `const` on specified version and later compiler (including beta and nightly) + #[const_fn("1.36")] + pub const fn version() { + /* ... */ + } + + // function is `const` on nightly compiler (including dev build) + #[const_fn(nightly)] + pub const fn nightly() { + /* ... */ + } + + // function is `const` if `cfg(...)` is true + #[const_fn(cfg(...))] + pub const fn cfg() { + /* ... */ + } + + // function is `const` if `cfg(feature = "...")` is true + #[const_fn(feature = "...")] + pub const fn feature() { + /* ... */ + } + ``` + +- Improve compile time by removing proc-macro related dependencies ([#18](https://github.com/taiki-e/const_fn/pull/18), [#20](https://github.com/taiki-e/const_fn/pull/20)). + +## [0.3.1] - 2019-12-09 + +- Updated `syn-mid` to 0.5. + +## [0.3.0] - 2019-10-20 + +- `#[const_fn]` attribute may only be used on const functions. + +## [0.2.1] - 2019-08-15 + +- Updated `proc-macro2`, `syn`, and `quote` to 1.0. + +- Updated `syn-mid` to 0.4. + +## [0.2.0] - 2019-06-16 + +- Transition to Rust 2018. With this change, the minimum required version will go up to Rust 1.31. + +## [0.1.7] - 2019-02-18 + +- Update syn-mid version to 0.3 + +## [0.1.6] - 2019-02-15 + +- Reduce compilation time + +## [0.1.5] - 2019-02-15 + +- Revert 0.1.4 + +## [0.1.4] - 2019-02-15 + +**Note: This release has been yanked.** + +- Reduce compilation time + +## [0.1.3] - 2019-01-06 + +- Fix dependencies + +## [0.1.2] - 2018-12-27 + +- Improve error messages + +## [0.1.1] - 2018-12-27 + +- Improve an error message + +## [0.1.0] - 2018-12-25 + +Initial release + +[Unreleased]: https://github.com/taiki-e/const_fn/compare/v0.4.5...HEAD +[0.4.5]: https://github.com/taiki-e/const_fn/compare/v0.4.4...v0.4.5 +[0.4.4]: https://github.com/taiki-e/const_fn/compare/v0.4.3...v0.4.4 +[0.4.3]: https://github.com/taiki-e/const_fn/compare/v0.4.2...v0.4.3 +[0.4.2]: https://github.com/taiki-e/const_fn/compare/v0.4.1...v0.4.2 +[0.4.1]: https://github.com/taiki-e/const_fn/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/taiki-e/const_fn/compare/v0.3.1...v0.4.0 +[0.3.1]: https://github.com/taiki-e/const_fn/compare/v0.3.0...v0.3.1 +[0.3.0]: https://github.com/taiki-e/const_fn/compare/v0.2.1...v0.3.0 +[0.2.1]: https://github.com/taiki-e/const_fn/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/taiki-e/const_fn/compare/v0.1.7...v0.2.0 +[0.1.7]: https://github.com/taiki-e/const_fn/compare/v0.1.6...v0.1.7 +[0.1.6]: https://github.com/taiki-e/const_fn/compare/v0.1.5...v0.1.6 +[0.1.5]: https://github.com/taiki-e/const_fn/compare/v0.1.4...v0.1.5 +[0.1.4]: https://github.com/taiki-e/const_fn/compare/v0.1.3...v0.1.4 +[0.1.3]: https://github.com/taiki-e/const_fn/compare/v0.1.2...v0.1.3 +[0.1.2]: https://github.com/taiki-e/const_fn/compare/v0.1.1...v0.1.2 +[0.1.1]: https://github.com/taiki-e/const_fn/compare/v0.1.0...v0.1.1 +[0.1.0]: https://github.com/taiki-e/const_fn/releases/tag/v0.1.0 diff --git a/third_party/cargo/vendor/const_fn-0.4.5/Cargo.toml b/third_party/cargo/vendor/const_fn-0.4.5/Cargo.toml new file mode 100644 index 0000000..6017735 --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "const_fn" +version = "0.4.5" +authors = ["Taiki Endo "] +exclude = ["/.github", "/scripts"] +description = "An attribute for easy generation of const functions with conditional compilations.\n" +documentation = "https://docs.rs/const_fn" +readme = "README.md" +keywords = ["macros", "attribute", "const", "static"] +categories = ["rust-patterns", "no-std"] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/taiki-e/const_fn" +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true diff --git a/third_party/cargo/vendor/const_fn-0.4.5/LICENSE-APACHE b/third_party/cargo/vendor/const_fn-0.4.5/LICENSE-APACHE new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/LICENSE-APACHE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/third_party/cargo/vendor/serde-1.0.110/LICENSE-MIT b/third_party/cargo/vendor/const_fn-0.4.5/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/serde-1.0.110/LICENSE-MIT rename to third_party/cargo/vendor/const_fn-0.4.5/LICENSE-MIT diff --git a/third_party/cargo/vendor/const_fn-0.4.5/README.md b/third_party/cargo/vendor/const_fn-0.4.5/README.md new file mode 100644 index 0000000..18feabe --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/README.md @@ -0,0 +1,71 @@ +# \#\[const_fn\] + +[![crates.io](https://img.shields.io/crates/v/const_fn.svg?style=flat-square&logo=rust)](https://crates.io/crates/const_fn) +[![docs.rs](https://img.shields.io/badge/docs.rs-const__fn-blue?style=flat-square)](https://docs.rs/const_fn) +[![license](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg?style=flat-square)](#license) +[![rustc](https://img.shields.io/badge/rustc-1.31+-blue.svg?style=flat-square)](https://www.rust-lang.org) +[![build status](https://img.shields.io/github/workflow/status/taiki-e/const_fn/CI/master?style=flat-square)](https://github.com/taiki-e/const_fn/actions?query=workflow%3ACI+branch%3Amaster) + +An attribute for easy generation of const functions with conditional +compilations. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +const_fn = "0.4" +``` + +*Compiler support: requires rustc 1.31+* + +## Examples + +```rust +use const_fn::const_fn; + +// function is `const` on specified version and later compiler (including beta and nightly) +#[const_fn("1.36")] +pub const fn version() { + /* ... */ +} + +// function is `const` on nightly compiler (including dev build) +#[const_fn(nightly)] +pub const fn nightly() { + /* ... */ +} + +// function is `const` if `cfg(...)` is true +#[const_fn(cfg(...))] +pub const fn cfg() { + /* ... */ +} + +// function is `const` if `cfg(feature = "...")` is true +#[const_fn(feature = "...")] +pub const fn feature() { + /* ... */ +} +``` + +## Alternatives + +This crate is proc-macro, but is very lightweight, and has no dependencies. + +You can manually define declarative macros with similar functionality (see +[`if_rust_version`](https://github.com/ogoffart/if_rust_version#examples)), +or [you can define the same function twice with different cfg](https://github.com/crossbeam-rs/crossbeam/blob/0b6ea5f69fde8768c1cfac0d3601e0b4325d7997/crossbeam-epoch/src/atomic.rs#L340-L372). +(Note: the former approach requires more macros to be defined depending on the +number of version requirements, the latter approach requires more functions to +be maintained manually) + +## License + +Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or +[MIT license](LICENSE-MIT) at your option. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/const_fn-0.4.5/build.rs b/third_party/cargo/vendor/const_fn-0.4.5/build.rs new file mode 100644 index 0000000..5aa341f --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/build.rs @@ -0,0 +1,102 @@ +#![forbid(unsafe_code)] +#![warn(rust_2018_idioms, single_use_lifetimes)] + +use std::{ + env, fs, + path::{Path, PathBuf}, + process::Command, + str, +}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let rustc: PathBuf = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()).into(); + let version = match Version::from_rustc(&rustc) { + Ok(version) => version.print(), + Err(e) => { + println!( + "cargo:warning={}: unable to determine rustc version: {}", + env!("CARGO_PKG_NAME"), + e + ); + return; + } + }; + + let out_dir: PathBuf = env::var_os("OUT_DIR").expect("OUT_DIR not set").into(); + let out_file = &out_dir.join("version"); + fs::write(out_file, version) + .unwrap_or_else(|e| panic!("failed to write {}: {}", out_file.display(), e)); + + // Mark as build script has been run successfully. + println!("cargo:rustc-cfg=const_fn_has_build_script"); +} + +struct Version { + minor: u32, + nightly: bool, +} + +impl Version { + // Based on https://github.com/cuviper/autocfg/blob/1.0.1/src/version.rs#L25-L59 + // + // TODO: use autocfg if https://github.com/cuviper/autocfg/issues/28 merged + // or https://github.com/taiki-e/const_fn/issues/27 rejected. + fn from_rustc(rustc: &Path) -> Result { + let output = + Command::new(rustc).args(&["--version", "--verbose"]).output().map_err(|e| { + format!("could not execute `{} --version --verbose`: {}", rustc.display(), e) + })?; + if !output.status.success() { + return Err(format!( + "process didn't exit successfully: `{} --version --verbose`", + rustc.display() + )); + } + let output = str::from_utf8(&output.stdout).map_err(|e| { + format!("failed to parse output of `{} --version --verbose`: {}", rustc.display(), e) + })?; + + // Find the release line in the verbose version output. + let release = output + .lines() + .find(|line| line.starts_with("release: ")) + .map(|line| &line["release: ".len()..]) + .ok_or_else(|| { + format!( + "could not find rustc release from output of `{} --version --verbose`: {}", + rustc.display(), + output + ) + })?; + + // Split the version and channel info. + let mut version_channel = release.split('-'); + let version = version_channel.next().unwrap(); + let channel = version_channel.next(); + + let minor = (|| { + // Split the version into semver components. + let mut digits = version.splitn(3, '.'); + let major = digits.next()?; + if major != "1" { + return None; + } + let minor = digits.next()?.parse().ok()?; + let _patch = digits.next()?; + Some(minor) + })() + .ok_or_else(|| { + format!("unexpected output from `{} --version --verbose`: {}", rustc.display(), output) + })?; + + let nightly = channel.map_or(false, |c| c == "dev" || c == "nightly"); + Ok(Self { minor, nightly }) + } + + fn print(&self) -> String { + format!("Version {{ minor: {}, nightly: {} }}\n", self.minor, self.nightly) + } +} diff --git a/third_party/cargo/vendor/const_fn-0.4.5/src/ast.rs b/third_party/cargo/vendor/const_fn-0.4.5/src/ast.rs new file mode 100644 index 0000000..3622a2f --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/src/ast.rs @@ -0,0 +1,141 @@ +use proc_macro::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree}; + +use crate::{ + iter::TokenIter, + to_tokens::ToTokens, + utils::{parse_as_empty, tt_span}, + Result, +}; + +pub(crate) struct Func { + pub(crate) attrs: Vec, + pub(crate) sig: Vec, + pub(crate) body: TokenTree, + pub(crate) print_const: bool, +} + +pub(crate) fn parse_input(input: TokenStream) -> Result { + let mut input = TokenIter::new(input); + + let attrs = parse_attrs(&mut input)?; + let sig = parse_signature(&mut input); + let body = input.next(); + parse_as_empty(input)?; + + if body.is_none() + || !sig + .iter() + .any(|tt| if let TokenTree::Ident(i) = tt { i.to_string() == "fn" } else { false }) + { + return Err(error!( + Span::call_site(), + "#[const_fn] attribute may only be used on functions" + )); + } + + Ok(Func { attrs, sig, body: body.unwrap(), print_const: true }) +} + +impl ToTokens for Func { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.attrs.iter().for_each(|attr| attr.to_tokens(tokens)); + if self.print_const { + self.sig.iter().for_each(|attr| attr.to_tokens(tokens)); + } else { + self.sig + .iter() + .filter( + |tt| if let TokenTree::Ident(i) = tt { i.to_string() != "const" } else { true }, + ) + .for_each(|tt| tt.to_tokens(tokens)); + } + self.body.to_tokens(tokens); + } +} + +fn parse_signature(input: &mut TokenIter) -> Vec { + let mut sig = Vec::new(); + let mut has_const = false; + loop { + match input.peek() { + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => break, + None => break, + Some(TokenTree::Ident(i)) if !has_const => { + match &*i.to_string() { + "const" => has_const = true, + "async" | "unsafe" | "extern" | "fn" => { + sig.push(TokenTree::Ident(Ident::new("const", i.span()))); + has_const = true; + } + _ => {} + } + sig.push(input.next().unwrap()); + } + Some(_) => sig.push(input.next().unwrap()), + } + } + sig +} + +fn parse_attrs(input: &mut TokenIter) -> Result> { + let mut attrs = Vec::new(); + loop { + let pound_token = match input.peek() { + Some(TokenTree::Punct(p)) if p.as_char() == '#' => input.next().unwrap(), + _ => break, + }; + let group = match input.peek() { + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => { + input.next().unwrap() + } + tt => return Err(error!(tt_span(tt), "expected `[`")), + }; + attrs.push(Attribute { pound_token, group }); + } + Ok(attrs) +} + +pub(crate) struct Attribute { + // `#` + pub(crate) pound_token: TokenTree, + // `[...]` + pub(crate) group: TokenTree, +} + +impl ToTokens for Attribute { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pound_token.to_tokens(tokens); + self.group.to_tokens(tokens); + } +} + +pub(crate) struct LitStr { + pub(crate) token: Literal, + value: String, +} + +impl LitStr { + pub(crate) fn new(token: Literal) -> Result { + let value = token.to_string(); + // unlike `syn::LitStr`, only accepts `"..."` + if value.starts_with('"') && value.ends_with('"') { + Ok(Self { token, value }) + } else { + Err(error!(token.span(), "expected string literal")) + } + } + + pub(crate) fn value(&self) -> &str { + &self.value[1..self.value.len() - 1] + } + + pub(crate) fn span(&self) -> Span { + self.token.span() + } +} + +impl ToTokens for LitStr { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } +} diff --git a/third_party/cargo/vendor/const_fn-0.4.5/src/error.rs b/third_party/cargo/vendor/const_fn-0.4.5/src/error.rs new file mode 100644 index 0000000..b572d5a --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/src/error.rs @@ -0,0 +1,37 @@ +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use std::iter::FromIterator; + +pub(crate) struct Error { + span: Span, + msg: String, +} + +impl Error { + pub(crate) fn new(span: Span, msg: impl Into) -> Self { + Self { span, msg: msg.into() } + } + + // https://github.com/dtolnay/syn/blob/1.0.39/src/error.rs#L218-L237 + pub(crate) fn to_compile_error(&self) -> TokenStream { + // compile_error!($msg) + TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("compile_error", self.span)), + TokenTree::Punct({ + let mut punct = Punct::new('!', Spacing::Alone); + punct.set_span(self.span); + punct + }), + TokenTree::Group({ + let mut group = Group::new(Delimiter::Brace, { + TokenStream::from_iter(vec![TokenTree::Literal({ + let mut string = Literal::string(&self.msg); + string.set_span(self.span); + string + })]) + }); + group.set_span(self.span); + group + }), + ]) + } +} diff --git a/third_party/cargo/vendor/const_fn-0.4.5/src/iter.rs b/third_party/cargo/vendor/const_fn-0.4.5/src/iter.rs new file mode 100644 index 0000000..f998dce --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/src/iter.rs @@ -0,0 +1,39 @@ +// Based on https://github.com/dtolnay/proc-macro-hack/blob/0.5.18/src/iter.rs + +use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; + +pub(crate) struct TokenIter { + stack: Vec, + peeked: Option, +} + +impl TokenIter { + pub(crate) fn new(tokens: TokenStream) -> Self { + Self { stack: vec![tokens.into_iter()], peeked: None } + } + + pub(crate) fn peek(&mut self) -> Option<&TokenTree> { + self.peeked = self.next(); + self.peeked.as_ref() + } +} + +impl Iterator for TokenIter { + type Item = TokenTree; + + fn next(&mut self) -> Option { + if let Some(tt) = self.peeked.take() { + return Some(tt); + } + loop { + let top = self.stack.last_mut()?; + match top.next() { + None => drop(self.stack.pop()), + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::None => { + self.stack.push(group.stream().into_iter()); + } + Some(tt) => return Some(tt), + } + } + } +} diff --git a/third_party/cargo/vendor/const_fn-0.4.5/src/lib.rs b/third_party/cargo/vendor/const_fn-0.4.5/src/lib.rs new file mode 100644 index 0000000..cd8e3e8 --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/src/lib.rs @@ -0,0 +1,233 @@ +//! An attribute for easy generation of const functions with conditional +//! compilations. +//! +//! # Examples +//! +//! ```rust +//! use const_fn::const_fn; +//! +//! // function is `const` on specified version and later compiler (including beta and nightly) +//! #[const_fn("1.36")] +//! pub const fn version() { +//! /* ... */ +//! } +//! +//! // function is `const` on nightly compiler (including dev build) +//! #[const_fn(nightly)] +//! pub const fn nightly() { +//! /* ... */ +//! } +//! +//! // function is `const` if `cfg(...)` is true +//! # #[cfg(any())] +//! #[const_fn(cfg(...))] +//! # pub fn _cfg() { unimplemented!() } +//! pub const fn cfg() { +//! /* ... */ +//! } +//! +//! // function is `const` if `cfg(feature = "...")` is true +//! #[const_fn(feature = "...")] +//! pub const fn feature() { +//! /* ... */ +//! } +//! ``` +//! +//! # Alternatives +//! +//! This crate is proc-macro, but is very lightweight, and has no dependencies. +//! +//! You can manually define declarative macros with similar functionality (see [`if_rust_version`](https://github.com/ogoffart/if_rust_version#examples)), or [you can define the same function twice with different cfg](https://github.com/crossbeam-rs/crossbeam/blob/0b6ea5f69fde8768c1cfac0d3601e0b4325d7997/crossbeam-epoch/src/atomic.rs#L340-L372). +//! (Note: the former approach requires more macros to be defined depending on the number of version requirements, the latter approach requires more functions to be maintained manually) + +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms, single_use_lifetimes), + allow(dead_code, unused_variables) + ) +))] +#![forbid(unsafe_code)] +#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)] +#![warn(clippy::all, clippy::default_trait_access)] + +// older compilers require explicit `extern crate`. +#[allow(unused_extern_crates)] +extern crate proc_macro; + +#[macro_use] +mod utils; + +mod ast; +mod error; +mod iter; +mod to_tokens; + +use proc_macro::{Delimiter, TokenStream, TokenTree}; +use std::str::FromStr; + +use crate::{ + ast::{Func, LitStr}, + error::Error, + to_tokens::ToTokens, + utils::{cfg_attrs, parse_as_empty, tt_span}, +}; + +type Result = std::result::Result; + +/// An attribute for easy generation of const functions with conditional compilations. +/// +/// See crate level documentation for details. +#[proc_macro_attribute] +pub fn const_fn(args: TokenStream, input: TokenStream) -> TokenStream { + let arg = match parse_arg(args) { + Ok(arg) => arg, + Err(e) => return e.to_compile_error(), + }; + let func = match ast::parse_input(input) { + Ok(func) => func, + Err(e) => return e.to_compile_error(), + }; + + expand(arg, func) +} + +fn expand(arg: Arg, mut func: Func) -> TokenStream { + match arg { + Arg::Cfg(cfg) => { + let (mut tokens, cfg_not) = cfg_attrs(cfg); + tokens.extend(func.to_token_stream()); + tokens.extend(cfg_not); + func.print_const = false; + tokens.extend(func.to_token_stream()); + tokens + } + Arg::Feature(feat) => { + let (mut tokens, cfg_not) = cfg_attrs(feat); + tokens.extend(func.to_token_stream()); + tokens.extend(cfg_not); + func.print_const = false; + tokens.extend(func.to_token_stream()); + tokens + } + Arg::Version(req) => { + if req.major > 1 || req.minor > VERSION.minor { + func.print_const = false; + } + func.to_token_stream() + } + Arg::Nightly => { + func.print_const = VERSION.nightly; + func.to_token_stream() + } + Arg::Always => func.to_token_stream(), + } +} + +enum Arg { + // `const_fn("...")` + Version(VersionReq), + // `const_fn(nightly)` + Nightly, + // `const_fn(cfg(...))` + Cfg(TokenStream), + // `const_fn(feature = "...")` + Feature(TokenStream), + // `const_fn` + Always, +} + +fn parse_arg(tokens: TokenStream) -> Result { + let mut iter = tokens.into_iter(); + + let next = iter.next(); + let next_span = tt_span(next.as_ref()); + match next { + None => return Ok(Arg::Always), + Some(TokenTree::Ident(i)) => match &*i.to_string() { + "nightly" => { + parse_as_empty(iter)?; + return Ok(Arg::Nightly); + } + "cfg" => { + return match iter.next().as_ref() { + Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => { + parse_as_empty(iter)?; + Ok(Arg::Cfg(g.stream())) + } + tt => Err(error!(tt_span(tt), "expected `(`")), + }; + } + "feature" => { + let next = iter.next(); + return match next.as_ref() { + Some(TokenTree::Punct(p)) if p.as_char() == '=' => match iter.next() { + Some(TokenTree::Literal(l)) => { + let l = LitStr::new(l)?; + parse_as_empty(iter)?; + Ok(Arg::Feature( + vec![TokenTree::Ident(i), next.unwrap(), l.token.into()] + .into_iter() + .collect(), + )) + } + tt => Err(error!(tt_span(tt.as_ref()), "expected string literal")), + }, + tt => Err(error!(tt_span(tt), "expected `=`")), + }; + } + _ => {} + }, + Some(TokenTree::Literal(l)) => { + if let Ok(l) = LitStr::new(l) { + parse_as_empty(iter)?; + return match l.value().parse::() { + Ok(req) => Ok(Arg::Version(req)), + Err(e) => Err(error!(l.span(), "{}", e)), + }; + } + } + Some(_) => {} + } + + Err(error!(next_span, "expected one of: `nightly`, `cfg`, `feature`, string literal")) +} + +struct VersionReq { + major: u32, + minor: u32, +} + +impl FromStr for VersionReq { + type Err = String; + + fn from_str(s: &str) -> Result { + let mut pieces = s.split('.'); + let major = pieces + .next() + .ok_or("need to specify the major version")? + .parse::() + .map_err(|e| e.to_string())?; + let minor = pieces + .next() + .ok_or("need to specify the minor version")? + .parse::() + .map_err(|e| e.to_string())?; + if let Some(s) = pieces.next() { + Err(format!("unexpected input: .{}", s)) + } else { + Ok(Self { major, minor }) + } + } +} + +struct Version { + minor: u32, + nightly: bool, +} + +#[cfg(const_fn_has_build_script)] +const VERSION: Version = include!(concat!(env!("OUT_DIR"), "/version")); +// If build script has not run or unable to determine version, it is considered as Rust 1.0. +#[cfg(not(const_fn_has_build_script))] +const VERSION: Version = Version { minor: 0, nightly: false }; diff --git a/third_party/cargo/vendor/const_fn-0.4.5/src/to_tokens.rs b/third_party/cargo/vendor/const_fn-0.4.5/src/to_tokens.rs new file mode 100644 index 0000000..771c7f6 --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/src/to_tokens.rs @@ -0,0 +1,36 @@ +use proc_macro::{Ident, Literal, TokenStream, TokenTree}; +use std::iter; + +pub(crate) trait ToTokens { + fn to_tokens(&self, tokens: &mut TokenStream); + + fn to_token_stream(&self) -> TokenStream { + let mut tokens = TokenStream::new(); + self.to_tokens(&mut tokens); + tokens + } +} + +impl ToTokens for Ident { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(iter::once(TokenTree::Ident(self.clone()))); + } +} + +impl ToTokens for Literal { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(iter::once(TokenTree::Literal(self.clone()))); + } +} + +impl ToTokens for TokenTree { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(iter::once(self.clone())); + } +} + +impl ToTokens for TokenStream { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.extend(self.clone()); + } +} diff --git a/third_party/cargo/vendor/const_fn-0.4.5/src/utils.rs b/third_party/cargo/vendor/const_fn-0.4.5/src/utils.rs new file mode 100644 index 0000000..e557ea5 --- /dev/null +++ b/third_party/cargo/vendor/const_fn-0.4.5/src/utils.rs @@ -0,0 +1,46 @@ +use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; +use std::iter::FromIterator; + +use crate::Result; + +macro_rules! error { + ($span:expr, $msg:expr) => {{ + crate::error::Error::new($span, $msg) + }}; + ($span:expr, $($tt:tt)*) => { + error!($span, format!($($tt)*)) + }; +} + +pub(crate) fn tt_span(tt: Option<&TokenTree>) -> Span { + tt.map_or_else(Span::call_site, TokenTree::span) +} + +pub(crate) fn parse_as_empty(mut tokens: impl Iterator) -> Result<()> { + match tokens.next() { + Some(tt) => Err(error!(tt.span(), "unexpected token: {}", tt)), + None => Ok(()), + } +} + +// (`#[cfg()]`, `#[cfg(not())]`) +pub(crate) fn cfg_attrs(tokens: TokenStream) -> (TokenStream, TokenStream) { + let f = |tokens| { + let tokens = TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("cfg", Span::call_site())), + TokenTree::Group(Group::new(Delimiter::Parenthesis, tokens)), + ]); + TokenStream::from_iter(vec![ + TokenTree::Punct(Punct::new('#', Spacing::Alone)), + TokenTree::Group(Group::new(Delimiter::Bracket, tokens)), + ]) + }; + + let cfg_not = TokenTree::Group(Group::new(Delimiter::Parenthesis, tokens.clone())); + let cfg_not = TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("not", Span::call_site())), + cfg_not, + ]); + + (f(tokens), f(cfg_not)) +} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/.cargo-checksum.json b/third_party/cargo/vendor/core-foundation-0.6.4/.cargo-checksum.json deleted file mode 100644 index 2983bd4..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"fae948ff1642562b5418d560bdf07378973a71245bf6305550f0fc0eaa6a94cf","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","src/array.rs":"221e81de15d95ca453df39466ba65faf879f2923202145958dfcebe63bfef97f","src/attributed_string.rs":"e6b32d673fa957611dbac2480675fab3c697fca8043077f2015f0a0801b20425","src/base.rs":"394764fa59518507fd8d53024b9574ab914eb856c1a873e6b1b4d84cdcde1c31","src/boolean.rs":"f5b4d295aaf6cc3681212afebeae2974c5d551125badcc066e6089ac0d2a0873","src/bundle.rs":"7e0fbe7032c8658ba5751a236eaaaa4b031fef43daf0be3aa229de4beb83b52a","src/data.rs":"a1d7e6430c745731fc7b2aee49af9f14e79c8a288951c82ea6507689a3356af8","src/date.rs":"a02f6cca7b6e8fbabc7713177429012658dba5146556e14a08e7baaf81958d83","src/dictionary.rs":"ed8080eb00507e342521fb2c513a83c5706e883c3f8d67d8f38e9a0ed685c7eb","src/error.rs":"22c21087d9c2c103d1bcb2c4af33b684317bbda5d4747902e510d410f8c1a14b","src/filedescriptor.rs":"f01da404e42760a50d91a43af648e781916c0a10c23753bea94f0f67bdc4d00c","src/lib.rs":"174cefb465af31d86e878ebcb5fb44cf3faed5bf3d568e9ada33136bd4bf3ef0","src/number.rs":"5a6cc9036c156e7e9d787864dd671087677abf4175cd840cbf123ccd89abcafe","src/propertylist.rs":"557ff9c346fbc70d19a887e0ce9977b84066f5d4bb6ba53ece8b733a5f0526e3","src/runloop.rs":"98334ee796cea1634a5a9baf59d62f02c25b718d45baab5230a5cc14cb2ee6d5","src/set.rs":"c61d7cacdbe7c3c69b2add3d2f1721960f6df710ef4db6a442cd8b05e8e929f3","src/string.rs":"28cead4283dfeeeb1c8c8bcf855823ed4b952e3a54cb8ca1c8f5f9a25d77bc0b","src/timezone.rs":"65859378232ee55f04bc4544b88f5dbc21f5db01bd16f2df3e82136ee3ce26b4","src/url.rs":"dd1798276b273654fb3f6c9ebb871548ca40c7f7b0bc2b94fdf4a7291f6dc601","src/uuid.rs":"c3457e43fc22ba0f3fcab3ee8108500585ba005dbcbfa7edad0d389701ddf379","tests/use_macro_outside_crate.rs":"ed5e74ac9e988f2609c0b785189f1e6368d693f6401603ad065521f3ab51df94"},"package":"25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/BUILD.bazel b/third_party/cargo/vendor/core-foundation-0.6.4/BUILD.bazel deleted file mode 100644 index dbdbbed..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/BUILD.bazel +++ /dev/null @@ -1,57 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "core_foundation", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.6.4", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/core-foundation-sys-0.6.2:core_foundation_sys", - "//third_party/cargo/vendor/libc-0.2.71:libc", - ], -) - -# Unsupported target "use_macro_outside_crate" with type "test" omitted diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/Cargo.toml b/third_party/cargo/vendor/core-foundation-0.6.4/Cargo.toml deleted file mode 100644 index b9bcf07..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "core-foundation" -version = "0.6.4" -authors = ["The Servo Project Developers"] -description = "Bindings to Core Foundation for macOS" -homepage = "https://github.com/servo/core-foundation-rs" -keywords = ["macos", "framework", "objc"] -categories = ["os::macos-apis"] -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/core-foundation-rs" -[dependencies.chrono] -version = "0.4" -optional = true - -[dependencies.core-foundation-sys] -version = "0.6.1" - -[dependencies.libc] -version = "0.2" - -[dependencies.uuid] -version = "0.5" -optional = true - -[features] -mac_os_10_7_support = ["core-foundation-sys/mac_os_10_7_support"] -mac_os_10_8_features = ["core-foundation-sys/mac_os_10_8_features"] -with-chrono = ["chrono"] -with-uuid = ["uuid"] diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/attributed_string.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/attributed_string.rs deleted file mode 100644 index e0fa576..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/attributed_string.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use core_foundation_sys::attributed_string::*; - -use base::TCFType; -use core_foundation_sys::base::{CFIndex, CFRange, kCFAllocatorDefault}; -use std::ptr::null; -use string::{CFString, CFStringRef}; - -declare_TCFType!{ - CFAttributedString, CFAttributedStringRef -} -impl_TCFType!(CFAttributedString, CFAttributedStringRef, CFAttributedStringGetTypeID); - -impl CFAttributedString { - #[inline] - pub fn new(string: &CFString) -> Self { - unsafe { - let astr_ref = CFAttributedStringCreate( - kCFAllocatorDefault, string.as_concrete_TypeRef(), null()); - - CFAttributedString::wrap_under_create_rule(astr_ref) - } - } - - #[inline] - pub fn char_len(&self) -> CFIndex { - unsafe { - CFAttributedStringGetLength(self.0) - } - } -} - -declare_TCFType!{ - CFMutableAttributedString, CFMutableAttributedStringRef -} -impl_TCFType!(CFMutableAttributedString, CFMutableAttributedStringRef, CFMutableAttributedStringGetTypeID); - -impl CFMutableAttributedString { - #[inline] - pub fn new() -> Self { - unsafe { - let astr_ref = CFAttributedStringCreateMutable( - kCFAllocatorDefault, 0); - - CFMutableAttributedString::wrap_under_create_rule(astr_ref) - } - } - - #[inline] - pub fn char_len(&self) -> CFIndex { - unsafe { - CFAttributedStringGetLength(self.0) - } - } - - #[inline] - pub fn replace_str(&mut self, string: &CFString, range: CFRange) { - unsafe { - CFAttributedStringReplaceString( - self.0, range, string.as_concrete_TypeRef()); - } - } - - #[inline] - pub fn set_attribute(&mut self, range: CFRange, name: CFStringRef, value: T) { - unsafe { - CFAttributedStringSetAttribute( - self.0, range, name, value.as_CFTypeRef()); - } - } -} - -impl Default for CFMutableAttributedString { - fn default() -> Self { - Self::new() - } -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/base.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/base.rs deleted file mode 100644 index 1a09ee6..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/base.rs +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std; -use std::fmt; -use std::marker::PhantomData; -use std::mem; -use std::mem::ManuallyDrop; -use std::ops::{Deref, DerefMut}; -use std::os::raw::c_void; - -pub use core_foundation_sys::base::*; - -use string::CFString; -use ConcreteCFType; - -pub trait CFIndexConvertible { - /// Always use this method to construct a `CFIndex` value. It performs bounds checking to - /// ensure the value is in range. - fn to_CFIndex(self) -> CFIndex; -} - -impl CFIndexConvertible for usize { - #[inline] - fn to_CFIndex(self) -> CFIndex { - let max_CFIndex = CFIndex::max_value(); - if self > (max_CFIndex as usize) { - panic!("value out of range") - } - self as CFIndex - } -} - -declare_TCFType!{ - /// Superclass of all Core Foundation objects. - CFType, CFTypeRef -} - -impl CFType { - /// Try to downcast the `CFType` to a subclass. Checking if the instance is the - /// correct subclass happens at runtime and `None` is returned if it is not the correct type. - /// Works similar to [`Box::downcast`] and [`CFPropertyList::downcast`]. - /// - /// # Examples - /// - /// ``` - /// # use core_foundation::string::CFString; - /// # use core_foundation::boolean::CFBoolean; - /// # use core_foundation::base::{CFType, TCFType}; - /// # - /// // Create a string. - /// let string: CFString = CFString::from_static_string("FooBar"); - /// // Cast it up to a CFType. - /// let cf_type: CFType = string.as_CFType(); - /// // Cast it down again. - /// assert_eq!(cf_type.downcast::().unwrap().to_string(), "FooBar"); - /// // Casting it to some other type will yield `None` - /// assert!(cf_type.downcast::().is_none()); - /// ``` - /// - /// ```compile_fail - /// # use core_foundation::array::CFArray; - /// # use core_foundation::base::TCFType; - /// # use core_foundation::boolean::CFBoolean; - /// # use core_foundation::string::CFString; - /// # - /// let boolean_array = CFArray::from_CFTypes(&[CFBoolean::true_value()]).into_CFType(); - /// - /// // This downcast is not allowed and causes compiler error, since it would cause undefined - /// // behavior to access the elements of the array as a CFString: - /// let invalid_string_array = boolean_array - /// .downcast_into::>() - /// .unwrap(); - /// ``` - /// - /// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast - /// [`CFPropertyList::downcast`]: ../propertylist/struct.CFPropertyList.html#method.downcast - #[inline] - pub fn downcast(&self) -> Option { - if self.instance_of::() { - unsafe { - let reference = T::Ref::from_void_ptr(self.0); - Some(T::wrap_under_get_rule(reference)) - } - } else { - None - } - } - - /// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count. - /// - /// [`downcast`]: #method.downcast - #[inline] - pub fn downcast_into(self) -> Option { - if self.instance_of::() { - unsafe { - let reference = T::Ref::from_void_ptr(self.0); - mem::forget(self); - Some(T::wrap_under_create_rule(reference)) - } - } else { - None - } - } -} - -impl fmt::Debug for CFType { - /// Formats the value using [`CFCopyDescription`]. - /// - /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let desc = unsafe { - CFString::wrap_under_create_rule(CFCopyDescription(self.0)) - }; - desc.fmt(f) - } -} - -impl Clone for CFType { - #[inline] - fn clone(&self) -> CFType { - unsafe { - TCFType::wrap_under_get_rule(self.0) - } - } -} - -impl PartialEq for CFType { - #[inline] - fn eq(&self, other: &CFType) -> bool { - unsafe { - CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 - } - } -} - -declare_TCFType!(CFAllocator, CFAllocatorRef); -impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID); - -impl CFAllocator { - #[inline] - pub fn new(mut context: CFAllocatorContext) -> CFAllocator { - unsafe { - let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context); - TCFType::wrap_under_create_rule(allocator_ref) - } - } -} - - -/// All Core Foundation types implement this trait. The associated type `Ref` specifies the -/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is -/// `CFArrayRef`. -/// -/// Most structs that implement this trait will do so via the [`impl_TCFType`] macro. -/// -/// [`impl_TCFType`]: ../macro.impl_TCFType.html -pub trait TCFType { - /// The reference type wrapped inside this type. - type Ref: TCFTypeRef; - - /// Returns the object as its concrete TypeRef. - fn as_concrete_TypeRef(&self) -> Self::Ref; - - /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this - /// when following Core Foundation's "Create Rule". The reference count is *not* bumped. - unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self; - - /// Returns the type ID for this class. - fn type_id() -> CFTypeID; - - /// Returns the object as a wrapped `CFType`. The reference count is incremented by one. - #[inline] - fn as_CFType(&self) -> CFType { - unsafe { - TCFType::wrap_under_get_rule(self.as_CFTypeRef()) - } - } - - /// Returns the object as a wrapped `CFType`. Consumes self and avoids changing the reference - /// count. - #[inline] - fn into_CFType(self) -> CFType - where - Self: Sized, - { - let reference = self.as_CFTypeRef(); - mem::forget(self); - unsafe { TCFType::wrap_under_create_rule(reference) } - } - - /// Returns the object as a raw `CFTypeRef`. The reference count is not adjusted. - fn as_CFTypeRef(&self) -> CFTypeRef; - - /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this - /// when following Core Foundation's "Get Rule". The reference count *is* bumped. - unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self; - - /// Returns the reference count of the object. It is unwise to do anything other than test - /// whether the return value of this method is greater than zero. - #[inline] - fn retain_count(&self) -> CFIndex { - unsafe { - CFGetRetainCount(self.as_CFTypeRef()) - } - } - - /// Returns the type ID of this object. - #[inline] - fn type_of(&self) -> CFTypeID { - unsafe { - CFGetTypeID(self.as_CFTypeRef()) - } - } - - /// Writes a debugging version of this object on standard error. - fn show(&self) { - unsafe { - CFShow(self.as_CFTypeRef()) - } - } - - /// Returns true if this value is an instance of another type. - #[inline] - fn instance_of(&self) -> bool { - self.type_of() == OtherCFType::type_id() - } -} - -impl TCFType for CFType { - type Ref = CFTypeRef; - - #[inline] - fn as_concrete_TypeRef(&self) -> CFTypeRef { - self.0 - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType { - let reference: CFTypeRef = CFRetain(reference); - TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> CFTypeRef { - self.as_concrete_TypeRef() - } - - #[inline] - unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType { - CFType(obj) - } - - #[inline] - fn type_id() -> CFTypeID { - // FIXME(pcwalton): Is this right? - 0 - } -} - -/// A reference to an element inside a container -pub struct ItemRef<'a, T: 'a>(ManuallyDrop, PhantomData<&'a T>); - -impl<'a, T> Deref for ItemRef<'a, T> { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} - -impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0.fmt(f) - } -} - -impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -/// A reference to a mutable element inside a container -pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop, PhantomData<&'a T>); - -impl<'a, T> Deref for ItemMutRef<'a, T> { - type Target = T; - - fn deref(&self) -> &T { - &self.0 - } -} - -impl<'a, T> DerefMut for ItemMutRef<'a, T> { - fn deref_mut(&mut self) -> &mut T { - &mut self.0 - } -} - -impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0.fmt(f) - } -} - -impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> { - fn eq(&self, other: &Self) -> bool { - self.0.eq(&other.0) - } -} - -/// A trait describing how to convert from the stored *mut c_void to the desired T -pub unsafe trait FromMutVoid { - unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized; -} - -unsafe impl FromMutVoid for u32 { - unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { - ItemMutRef(ManuallyDrop::new(x as u32), PhantomData) - } -} - -unsafe impl FromMutVoid for *const c_void { - unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { - ItemMutRef(ManuallyDrop::new(x), PhantomData) - } -} - -unsafe impl FromMutVoid for T { - unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { - ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) - } -} - -/// A trait describing how to convert from the stored *const c_void to the desired T -pub unsafe trait FromVoid { - unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized; -} - -unsafe impl FromVoid for u32 { - unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { - // Functions like CGFontCopyTableTags treat the void*'s as u32's - // so we convert by casting directly - ItemRef(ManuallyDrop::new(x as u32), PhantomData) - } -} - -unsafe impl FromVoid for *const c_void { - unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { - ItemRef(ManuallyDrop::new(x), PhantomData) - } -} - -unsafe impl FromVoid for T { - unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { - ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) - } -} - -/// A trait describing how to convert from the stored *const c_void to the desired T -pub unsafe trait ToVoid { - fn to_void(&self) -> *const c_void; -} - -unsafe impl ToVoid<*const c_void> for *const c_void { - fn to_void(&self) -> *const c_void { - *self - } -} - -unsafe impl<'a> ToVoid for &'a CFType { - fn to_void(&self) -> *const ::std::os::raw::c_void { - self.as_concrete_TypeRef().as_void_ptr() - } -} - -unsafe impl ToVoid for CFType { - fn to_void(&self) -> *const ::std::os::raw::c_void { - self.as_concrete_TypeRef().as_void_ptr() - } -} - -unsafe impl ToVoid for CFTypeRef { - fn to_void(&self) -> *const ::std::os::raw::c_void { - self.as_void_ptr() - } -} - - -#[cfg(test)] -mod tests { - use super::*; - use std::mem; - use boolean::CFBoolean; - - #[test] - fn cftype_instance_of() { - let string = CFString::from_static_string("foo"); - let cftype = string.as_CFType(); - - assert!(cftype.instance_of::()); - assert!(!cftype.instance_of::()); - } - - #[test] - fn as_cftype_retain_count() { - let string = CFString::from_static_string("bar"); - assert_eq!(string.retain_count(), 1); - let cftype = string.as_CFType(); - assert_eq!(cftype.retain_count(), 2); - mem::drop(string); - assert_eq!(cftype.retain_count(), 1); - } - - #[test] - fn into_cftype_retain_count() { - let string = CFString::from_static_string("bar"); - assert_eq!(string.retain_count(), 1); - let cftype = string.into_CFType(); - assert_eq!(cftype.retain_count(), 1); - } - - #[test] - fn as_cftype_and_downcast() { - let string = CFString::from_static_string("bar"); - let cftype = string.as_CFType(); - let string2 = cftype.downcast::().unwrap(); - assert_eq!(string2.to_string(), "bar"); - - assert_eq!(string.retain_count(), 3); - assert_eq!(cftype.retain_count(), 3); - assert_eq!(string2.retain_count(), 3); - } - - #[test] - fn into_cftype_and_downcast_into() { - let string = CFString::from_static_string("bar"); - let cftype = string.into_CFType(); - let string2 = cftype.downcast_into::().unwrap(); - assert_eq!(string2.to_string(), "bar"); - assert_eq!(string2.retain_count(), 1); - } -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/bundle.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/bundle.rs deleted file mode 100644 index f23f9ae..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/bundle.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Core Foundation Bundle Type - -pub use core_foundation_sys::bundle::*; -use core_foundation_sys::base::kCFAllocatorDefault; - -use base::{CFType, TCFType}; -use url::CFURL; -use dictionary::CFDictionary; -use std::os::raw::c_void; -use string::CFString; - -declare_TCFType!{ - /// A Bundle type. - CFBundle, CFBundleRef -} -impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID); - -impl CFBundle { - pub fn new(bundleURL: CFURL) -> Option { - unsafe { - let bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundleURL.as_concrete_TypeRef()); - if bundle_ref.is_null() { - None - } else { - Some(TCFType::wrap_under_create_rule(bundle_ref)) - } - } - } - - pub fn bundle_with_identifier(identifier: CFString) -> Option { - unsafe { - let bundle_ref = CFBundleGetBundleWithIdentifier(identifier.as_concrete_TypeRef()); - if bundle_ref.is_null() { - None - } else { - Some(TCFType::wrap_under_get_rule(bundle_ref)) - } - } - } - - pub fn function_pointer_for_name(&self, function_name: CFString) -> *const c_void { - unsafe { - CFBundleGetFunctionPointerForName(self.as_concrete_TypeRef(), - function_name.as_concrete_TypeRef()) - } - } - - pub fn main_bundle() -> CFBundle { - unsafe { - let bundle_ref = CFBundleGetMainBundle(); - TCFType::wrap_under_get_rule(bundle_ref) - } - } - - pub fn info_dictionary(&self) -> CFDictionary { - unsafe { - let info_dictionary = CFBundleGetInfoDictionary(self.0); - TCFType::wrap_under_get_rule(info_dictionary) - } - } - - pub fn executable_url(&self) -> Option { - unsafe { - let exe_url = CFBundleCopyExecutableURL(self.0); - if exe_url.is_null() { - None - } else { - Some(TCFType::wrap_under_create_rule(exe_url)) - } - } - } - - pub fn private_frameworks_url(&self) -> Option { - unsafe { - let fw_url = CFBundleCopyPrivateFrameworksURL(self.0); - if fw_url.is_null() { - None - } else { - Some(TCFType::wrap_under_create_rule(fw_url)) - } - } - } -} - - -#[test] -fn safari_executable_url() { - use string::CFString; - use url::{CFURL, kCFURLPOSIXPathStyle}; - - let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); - let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); - let cfurl_executable = CFBundle::new(cfurl_path) - .expect("Safari not present") - .executable_url(); - assert!(cfurl_executable.is_some()); - assert_eq!(cfurl_executable - .unwrap() - .absolute() - .get_file_system_path(kCFURLPOSIXPathStyle) - .to_string(), - "/Applications/Safari.app/Contents/MacOS/Safari"); -} - -#[test] -fn safari_private_frameworks_url() { - use string::CFString; - use url::{CFURL, kCFURLPOSIXPathStyle}; - - let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); - let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); - let cfurl_executable = CFBundle::new(cfurl_path) - .expect("Safari not present") - .private_frameworks_url(); - assert!(cfurl_executable.is_some()); - assert_eq!(cfurl_executable - .unwrap() - .absolute() - .get_file_system_path(kCFURLPOSIXPathStyle) - .to_string(), - "/Applications/Safari.app/Contents/Frameworks"); -} - -#[test] -fn non_existant_bundle() { - use string::CFString; - use url::{CFURL, kCFURLPOSIXPathStyle}; - - let cfstr_path = CFString::from_static_string("/usr/local/foo"); - let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); - assert!(CFBundle::new(cfurl_path).is_none()); -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/lib.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/lib.rs deleted file mode 100644 index cbffbd9..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/lib.rs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_snake_case)] - -//! This crate provides wrappers around the underlying CoreFoundation -//! types and functions that are available on Apple's operating systems. -//! -//! It also provides a framework for other crates to use when wrapping -//! other frameworks that use the CoreFoundation framework. - -extern crate core_foundation_sys; -extern crate libc; - -#[cfg(feature = "with-chrono")] -extern crate chrono; - -use base::TCFType; - -pub unsafe trait ConcreteCFType: TCFType {} - -/// Declare a Rust type that wraps an underlying CoreFoundation type. -/// -/// This will provide an implementation of `Drop` using [`CFRelease`]. -/// The type must have an implementation of the [`TCFType`] trait, usually -/// provided using the [`impl_TCFType`] macro. -/// -/// ``` -/// #[macro_use] extern crate core_foundation; -/// // Make sure that the `TCFType` trait is in scope. -/// use core_foundation::base::{CFTypeID, TCFType}; -/// -/// extern "C" { -/// // We need a function that returns the `CFTypeID`. -/// pub fn ShrubberyGetTypeID() -> CFTypeID; -/// } -/// -/// pub struct __Shrubbery {} -/// // The ref type must be a pointer to the underlying struct. -/// pub type ShrubberyRef = *const __Shrubbery; -/// -/// declare_TCFType!(Shrubbery, ShrubberyRef); -/// impl_TCFType!(Shrubbery, ShrubberyRef, ShrubberyGetTypeID); -/// # fn main() {} -/// ``` -/// -/// [`CFRelease`]: https://developer.apple.com/documentation/corefoundation/1521153-cfrelease -/// [`TCFType`]: base/trait.TCFType.html -/// [`impl_TCFType`]: macro.impl_TCFType.html -#[macro_export] -macro_rules! declare_TCFType { - ( - $(#[$doc:meta])* - $ty:ident, $raw:ident - ) => { - $(#[$doc])* - pub struct $ty($raw); - - impl Drop for $ty { - fn drop(&mut self) { - unsafe { $crate::base::CFRelease(self.as_CFTypeRef()) } - } - } - } -} - -/// Provide an implementation of the [`TCFType`] trait for the Rust -/// wrapper type around an underlying CoreFoundation type. -/// -/// See [`declare_TCFType`] for details. -/// -/// [`declare_TCFType`]: macro.declare_TCFType.html -/// [`TCFType`]: base/trait.TCFType.html -#[macro_export] -macro_rules! impl_TCFType { - ($ty:ident, $ty_ref:ident, $ty_id:ident) => { - impl_TCFType!($ty<>, $ty_ref, $ty_id); - unsafe impl $crate::ConcreteCFType for $ty { } - }; - - ($ty:ident<$($p:ident $(: $bound:path)*),*>, $ty_ref:ident, $ty_id:ident) => { - impl<$($p $(: $bound)*),*> $crate::base::TCFType for $ty<$($p),*> { - type Ref = $ty_ref; - - #[inline] - fn as_concrete_TypeRef(&self) -> $ty_ref { - self.0 - } - - #[inline] - unsafe fn wrap_under_get_rule(reference: $ty_ref) -> Self { - let reference = $crate::base::CFRetain(reference as *const ::std::os::raw::c_void) as $ty_ref; - $crate::base::TCFType::wrap_under_create_rule(reference) - } - - #[inline] - fn as_CFTypeRef(&self) -> $crate::base::CFTypeRef { - self.as_concrete_TypeRef() as $crate::base::CFTypeRef - } - - #[inline] - unsafe fn wrap_under_create_rule(reference: $ty_ref) -> Self { - // we need one PhantomData for each type parameter so call ourselves - // again with @Phantom $p to produce that - $ty(reference $(, impl_TCFType!(@Phantom $p))*) - } - - #[inline] - fn type_id() -> $crate::base::CFTypeID { - unsafe { - $ty_id() - } - } - } - - impl Clone for $ty { - #[inline] - fn clone(&self) -> $ty { - unsafe { - $ty::wrap_under_get_rule(self.0) - } - } - } - - impl PartialEq for $ty { - #[inline] - fn eq(&self, other: &$ty) -> bool { - self.as_CFType().eq(&other.as_CFType()) - } - } - - impl Eq for $ty { } - - unsafe impl<'a> $crate::base::ToVoid<$ty> for &'a $ty { - fn to_void(&self) -> *const ::std::os::raw::c_void { - use $crate::base::TCFTypeRef; - self.as_concrete_TypeRef().as_void_ptr() - } - } - - unsafe impl $crate::base::ToVoid<$ty> for $ty { - fn to_void(&self) -> *const ::std::os::raw::c_void { - use $crate::base::TCFTypeRef; - self.as_concrete_TypeRef().as_void_ptr() - } - } - - unsafe impl $crate::base::ToVoid<$ty> for $ty_ref { - fn to_void(&self) -> *const ::std::os::raw::c_void { - use $crate::base::TCFTypeRef; - self.as_void_ptr() - } - } - - }; - - (@Phantom $x:ident) => { ::std::marker::PhantomData }; -} - - -/// Implement `std::fmt::Debug` for the given type. -/// -/// This will invoke the implementation of `Debug` for [`CFType`] -/// which invokes [`CFCopyDescription`]. -/// -/// The type must have an implementation of the [`TCFType`] trait, usually -/// provided using the [`impl_TCFType`] macro. -/// -/// [`CFType`]: base/struct.CFType.html#impl-Debug -/// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc -/// [`TCFType`]: base/trait.TCFType.html -/// [`impl_TCFType`]: macro.impl_TCFType.html -#[macro_export] -macro_rules! impl_CFTypeDescription { - ($ty:ident) => { - // it's fine to use an empty <> list - impl_CFTypeDescription!($ty<>); - }; - ($ty:ident<$($p:ident $(: $bound:path)*),*>) => { - impl<$($p $(: $bound)*),*> ::std::fmt::Debug for $ty<$($p),*> { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - self.as_CFType().fmt(f) - } - } - } -} - -#[macro_export] -macro_rules! impl_CFComparison { - ($ty:ident, $compare:ident) => { - impl PartialOrd for $ty { - #[inline] - fn partial_cmp(&self, other: &$ty) -> Option<::std::cmp::Ordering> { - unsafe { - Some($compare(self.as_concrete_TypeRef(), other.as_concrete_TypeRef(), ::std::ptr::null_mut()).into()) - } - } - } - - impl Ord for $ty { - #[inline] - fn cmp(&self, other: &$ty) -> ::std::cmp::Ordering { - self.partial_cmp(other).unwrap() - } - } - } -} - -pub mod array; -pub mod attributed_string; -pub mod base; -pub mod boolean; -pub mod data; -pub mod date; -pub mod dictionary; -pub mod error; -pub mod filedescriptor; -pub mod number; -pub mod set; -pub mod string; -pub mod url; -pub mod bundle; -pub mod propertylist; -pub mod runloop; -pub mod timezone; -pub mod uuid; diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/runloop.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/runloop.rs deleted file mode 100644 index 24aa9a5..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/runloop.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_upper_case_globals)] - -pub use core_foundation_sys::runloop::*; -use core_foundation_sys::base::CFIndex; -use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; -use core_foundation_sys::string::CFStringRef; - -use base::{TCFType}; -use date::{CFAbsoluteTime, CFTimeInterval}; -use filedescriptor::CFFileDescriptor; -use string::{CFString}; - -pub type CFRunLoopMode = CFStringRef; - - -declare_TCFType!(CFRunLoop, CFRunLoopRef); -impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); -impl_CFTypeDescription!(CFRunLoop); - -impl CFRunLoop { - pub fn get_current() -> CFRunLoop { - unsafe { - let run_loop_ref = CFRunLoopGetCurrent(); - TCFType::wrap_under_get_rule(run_loop_ref) - } - } - - pub fn get_main() -> CFRunLoop { - unsafe { - let run_loop_ref = CFRunLoopGetMain(); - TCFType::wrap_under_get_rule(run_loop_ref) - } - } - - pub fn run_current() { - unsafe { - CFRunLoopRun(); - } - } - - pub fn stop(&self) { - unsafe { - CFRunLoopStop(self.0); - } - } - - pub fn current_mode(&self) -> Option { - unsafe { - let string_ref = CFRunLoopCopyCurrentMode(self.0); - if string_ref.is_null() { - return None; - } - - let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref); - Some(cf_string.to_string()) - } - } - - pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool { - unsafe { - CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 - } - } - - pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { - unsafe { - CFRunLoopAddTimer(self.0, timer.0, mode); - } - } - - pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { - unsafe { - CFRunLoopRemoveTimer(self.0, timer.0, mode); - } - } - - pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool { - unsafe { - CFRunLoopContainsSource(self.0, source.0, mode) != 0 - } - } - - pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { - unsafe { - CFRunLoopAddSource(self.0, source.0, mode); - } - } - - pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { - unsafe { - CFRunLoopRemoveSource(self.0, source.0, mode); - } - } - - pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool { - unsafe { - CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 - } - } - - pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { - unsafe { - CFRunLoopAddObserver(self.0, observer.0, mode); - } - } - - pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { - unsafe { - CFRunLoopRemoveObserver(self.0, observer.0, mode); - } - } - -} - - -declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef); -impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); - -impl CFRunLoopTimer { - pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { - unsafe { - let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context); - TCFType::wrap_under_create_rule(timer_ref) - } - } -} - - -declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef); -impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); - -impl CFRunLoopSource { - pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option { - fd.to_run_loop_source(order) - } -} - -declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef); -impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID); - -#[cfg(test)] -mod test { - use super::*; - use date::{CFDate, CFAbsoluteTime}; - use std::mem; - use std::os::raw::c_void; - use std::sync::mpsc; - - #[test] - fn wait_200_milliseconds() { - let run_loop = CFRunLoop::get_current(); - - let now = CFDate::now().abs_time(); - let (elapsed_tx, elapsed_rx) = mpsc::channel(); - let mut info = Info { - start_time: now, - elapsed_tx, - }; - let mut context = unsafe { CFRunLoopTimerContext { - version: 0, - info: &mut info as *mut _ as *mut c_void, - retain: mem::zeroed(), - release: mem::zeroed(), - copyDescription: mem::zeroed(), - } }; - - - let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); - unsafe { - run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); - } - CFRunLoop::run_current(); - let elapsed = elapsed_rx.try_recv().unwrap(); - println!("wait_200_milliseconds, elapsed: {}", elapsed); - assert!(elapsed > 0.19 && elapsed < 0.30); - } - - struct Info { - start_time: CFAbsoluteTime, - elapsed_tx: mpsc::Sender, - } - - extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void) { - let info: *mut Info = unsafe { mem::transmute(raw_info) }; - let now = CFDate::now().abs_time(); - let elapsed = now - unsafe { (*info).start_time }; - let _ = unsafe { (*info).elapsed_tx.send(elapsed) }; - CFRunLoop::get_current().stop(); - } -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/set.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/set.rs deleted file mode 100644 index f06d8a3..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/set.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An immutable bag of elements. - -pub use core_foundation_sys::set::*; -use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault}; - -use base::{CFIndexConvertible, TCFType}; - -use std::os::raw::c_void; -use std::marker::PhantomData; - -/// An immutable bag of elements. -pub struct CFSet(CFSetRef, PhantomData); - -impl Drop for CFSet { - fn drop(&mut self) { - unsafe { CFRelease(self.as_CFTypeRef()) } - } -} - -impl_TCFType!(CFSet, CFSetRef, CFSetGetTypeID); -impl_CFTypeDescription!(CFSet); - -impl CFSet { - /// Creates a new set from a list of `CFType` instances. - pub fn from_slice(elems: &[T]) -> CFSet where T: TCFType { - unsafe { - let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); - let set_ref = CFSetCreate(kCFAllocatorDefault, - elems.as_ptr(), - elems.len().to_CFIndex(), - &kCFTypeSetCallBacks); - TCFType::wrap_under_create_rule(set_ref) - } - } -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/string.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/string.rs deleted file mode 100644 index 021479c..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/string.rs +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Immutable strings. - -pub use core_foundation_sys::string::*; - -use base::{CFIndexConvertible, TCFType}; - -use core_foundation_sys::base::{Boolean, CFIndex, CFRange}; -use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull}; -use std::borrow::Cow; -use std::fmt; -use std::str::{self, FromStr}; -use std::ptr; -use std::ffi::CStr; - - -declare_TCFType!{ - /// An immutable string in one of a variety of encodings. - CFString, CFStringRef -} -impl_TCFType!(CFString, CFStringRef, CFStringGetTypeID); - -impl FromStr for CFString { - type Err = (); - - /// See also CFString::new for a variant of this which does not return a Result - #[inline] - fn from_str(string: &str) -> Result { - Ok(CFString::new(string)) - } -} - -impl<'a> From<&'a str> for CFString { - #[inline] - fn from(string: &'a str) -> CFString { - CFString::new(string) - } -} - -impl<'a> From<&'a CFString> for Cow<'a, str> { - fn from(cf_str: &'a CFString) -> Cow<'a, str> { - unsafe { - // Do this without allocating if we can get away with it - let c_string = CFStringGetCStringPtr(cf_str.0, kCFStringEncodingUTF8); - if !c_string.is_null() { - let c_str = CStr::from_ptr(c_string); - Cow::Borrowed(str::from_utf8_unchecked(c_str.to_bytes())) - } else { - let char_len = cf_str.char_len(); - - // First, ask how big the buffer ought to be. - let mut bytes_required: CFIndex = 0; - CFStringGetBytes(cf_str.0, - CFRange { location: 0, length: char_len }, - kCFStringEncodingUTF8, - 0, - false as Boolean, - ptr::null_mut(), - 0, - &mut bytes_required); - - // Then, allocate the buffer and actually copy. - let mut buffer = vec![b'\x00'; bytes_required as usize]; - - let mut bytes_used: CFIndex = 0; - let chars_written = CFStringGetBytes(cf_str.0, - CFRange { location: 0, length: char_len }, - kCFStringEncodingUTF8, - 0, - false as Boolean, - buffer.as_mut_ptr(), - buffer.len().to_CFIndex(), - &mut bytes_used); - assert_eq!(chars_written, char_len); - - // This is dangerous; we over-allocate and null-terminate the string (during - // initialization). - assert_eq!(bytes_used, buffer.len().to_CFIndex()); - Cow::Owned(String::from_utf8_unchecked(buffer)) - } - } - } -} - -impl fmt::Display for CFString { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(&Cow::from(self)) - } -} - -impl fmt::Debug for CFString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "\"{}\"", self) - } -} - - -impl CFString { - /// Creates a new `CFString` instance from a Rust string. - #[inline] - pub fn new(string: &str) -> CFString { - unsafe { - let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault, - string.as_ptr(), - string.len().to_CFIndex(), - kCFStringEncodingUTF8, - false as Boolean); - CFString::wrap_under_create_rule(string_ref) - } - } - - /// Like `CFString::new`, but references a string that can be used as a backing store - /// by virtue of being statically allocated. - #[inline] - pub fn from_static_string(string: &'static str) -> CFString { - unsafe { - let string_ref = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, - string.as_ptr(), - string.len().to_CFIndex(), - kCFStringEncodingUTF8, - false as Boolean, - kCFAllocatorNull); - TCFType::wrap_under_create_rule(string_ref) - } - } - - /// Returns the number of characters in the string. - #[inline] - pub fn char_len(&self) -> CFIndex { - unsafe { - CFStringGetLength(self.0) - } - } -} - -#[test] -fn string_and_back() { - let original = "The quick brown fox jumped over the slow lazy dog."; - let cfstr = CFString::from_static_string(original); - let converted = cfstr.to_string(); - assert_eq!(converted, original); -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/timezone.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/timezone.rs deleted file mode 100644 index 66aadb7..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/timezone.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Core Foundation time zone objects. - -pub use core_foundation_sys::timezone::*; -use core_foundation_sys::base::kCFAllocatorDefault; - -use base::TCFType; -use date::{CFDate, CFTimeInterval}; - -#[cfg(feature = "with-chrono")] -use chrono::{FixedOffset, NaiveDateTime}; - - -declare_TCFType!{ - /// A time zone. - CFTimeZone, CFTimeZoneRef -} -impl_TCFType!(CFTimeZone, CFTimeZoneRef, CFTimeZoneGetTypeID); -impl_CFTypeDescription!(CFTimeZone); - -impl Default for CFTimeZone { - fn default() -> CFTimeZone { - unsafe { - let tz_ref = CFTimeZoneCopyDefault(); - TCFType::wrap_under_create_rule(tz_ref) - } - } -} - -impl CFTimeZone { - #[inline] - pub fn new(interval: CFTimeInterval) -> CFTimeZone { - unsafe { - let tz_ref = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, interval); - TCFType::wrap_under_create_rule(tz_ref) - } - } - - #[inline] - pub fn system() -> CFTimeZone { - unsafe { - let tz_ref = CFTimeZoneCopySystem(); - TCFType::wrap_under_create_rule(tz_ref) - } - } - - pub fn seconds_from_gmt(&self, date: CFDate) -> CFTimeInterval { - unsafe { - CFTimeZoneGetSecondsFromGMT(self.0, date.abs_time()) - } - } - - #[cfg(feature = "with-chrono")] - pub fn offset_at_date(&self, date: NaiveDateTime) -> FixedOffset { - let date = CFDate::from_naive_utc(date); - FixedOffset::east(self.seconds_from_gmt(date) as i32) - } - - #[cfg(feature = "with-chrono")] - pub fn from_offset(offset: FixedOffset) -> CFTimeZone { - CFTimeZone::new(offset.local_minus_utc() as f64) - } -} - -#[cfg(test)] -mod test { - use super::CFTimeZone; - - #[cfg(feature = "with-chrono")] - use chrono::{NaiveDateTime, FixedOffset}; - - #[test] - fn timezone_comparison() { - let system = CFTimeZone::system(); - let default = CFTimeZone::default(); - assert_eq!(system, default); - } - - #[test] - #[cfg(feature = "with-chrono")] - fn timezone_chrono_conversion() { - let offset = FixedOffset::west(28800); - let tz = CFTimeZone::from_offset(offset); - let converted = tz.offset_at_date(NaiveDateTime::from_timestamp(0, 0)); - assert_eq!(offset, converted); - } -} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/url.rs b/third_party/cargo/vendor/core-foundation-0.6.4/src/url.rs deleted file mode 100644 index 199ad2e..0000000 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/url.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A URL type for Core Foundation. - -pub use core_foundation_sys::url::*; - -use base::{TCFType, CFIndex}; -use string::{CFString}; - -use core_foundation_sys::base::{kCFAllocatorDefault, Boolean}; -use std::fmt; -use std::ptr; -use std::path::{Path, PathBuf}; -use std::mem; - -use libc::{c_char, strlen, PATH_MAX}; - -#[cfg(unix)] -use std::os::unix::ffi::OsStrExt; -#[cfg(unix)] -use std::ffi::OsStr; - - -declare_TCFType!(CFURL, CFURLRef); -impl_TCFType!(CFURL, CFURLRef, CFURLGetTypeID); - -impl fmt::Debug for CFURL { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - unsafe { - let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0)); - write!(f, "{}", string.to_string()) - } - } -} - -impl CFURL { - pub fn from_path>(path: P, isDirectory: bool) -> Option { - let path_bytes; - #[cfg(unix)] - { - path_bytes = path.as_ref().as_os_str().as_bytes() - } - #[cfg(not(unix))] - { - // XXX: Getting non-valid UTF8 paths into CoreFoundation on Windows is going to be unpleasant - // CFURLGetWideFileSystemRepresentation might help - path_bytes = match path.as_ref().to_str() { - Some(path) => path, - None => return None, - } - } - - unsafe { - let url_ref = CFURLCreateFromFileSystemRepresentation(ptr::null_mut(), path_bytes.as_ptr(), path_bytes.len() as CFIndex, isDirectory as u8); - if url_ref.is_null() { - return None; - } - Some(TCFType::wrap_under_create_rule(url_ref)) - } - } - - pub fn from_file_system_path(filePath: CFString, pathStyle: CFURLPathStyle, isDirectory: bool) -> CFURL { - unsafe { - let url_ref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath.as_concrete_TypeRef(), pathStyle, isDirectory as u8); - TCFType::wrap_under_create_rule(url_ref) - } - } - - #[cfg(unix)] - pub fn to_path(&self) -> Option { - // implementing this on Windows is more complicated because of the different OsStr representation - unsafe { - let mut buf: [u8; PATH_MAX as usize] = mem::uninitialized(); - let result = CFURLGetFileSystemRepresentation(self.0, true as Boolean, buf.as_mut_ptr(), buf.len() as CFIndex); - if result == false as Boolean { - return None; - } - let len = strlen(buf.as_ptr() as *const c_char); - let path = OsStr::from_bytes(&buf[0..len]); - Some(PathBuf::from(path)) - } - } - - pub fn get_string(&self) -> CFString { - unsafe { - TCFType::wrap_under_get_rule(CFURLGetString(self.0)) - } - } - - pub fn get_file_system_path(&self, pathStyle: CFURLPathStyle) -> CFString { - unsafe { - TCFType::wrap_under_create_rule(CFURLCopyFileSystemPath(self.as_concrete_TypeRef(), pathStyle)) - } - } - - pub fn absolute(&self) -> CFURL { - unsafe { - TCFType::wrap_under_create_rule(CFURLCopyAbsoluteURL(self.as_concrete_TypeRef())) - } - } -} - -#[test] -fn file_url_from_path() { - let path = "/usr/local/foo/"; - let cfstr_path = CFString::from_static_string(path); - let cfurl = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); - assert_eq!(cfurl.get_string().to_string(), "file:///usr/local/foo/"); -} - -#[cfg(unix)] -#[test] -fn non_utf8() { - use std::ffi::OsStr; - let path = Path::new(OsStr::from_bytes(b"/\xC0/blame")); - let cfurl = CFURL::from_path(path, false).unwrap(); - assert_eq!(cfurl.to_path().unwrap(), path); - let len = unsafe { CFURLGetBytes(cfurl.as_concrete_TypeRef(), ptr::null_mut(), 0) }; - assert_eq!(len, 17); -} - -#[test] -fn absolute_file_url() { - use core_foundation_sys::url::CFURLCreateWithFileSystemPathRelativeToBase; - use std::path::PathBuf; - - let path = "/usr/local/foo"; - let file = "bar"; - - let cfstr_path = CFString::from_static_string(path); - let cfstr_file = CFString::from_static_string(file); - let cfurl_base = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); - let cfurl_relative: CFURL = unsafe { - let url_ref = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, - cfstr_file.as_concrete_TypeRef(), - kCFURLPOSIXPathStyle, - false as u8, - cfurl_base.as_concrete_TypeRef()); - TCFType::wrap_under_create_rule(url_ref) - }; - - let mut absolute_path = PathBuf::from(path); - absolute_path.push(file); - - assert_eq!(cfurl_relative.get_file_system_path(kCFURLPOSIXPathStyle).to_string(), file); - assert_eq!(cfurl_relative.absolute().get_file_system_path(kCFURLPOSIXPathStyle).to_string(), - absolute_path.to_str().unwrap()); -} diff --git a/third_party/cargo/vendor/core-foundation-0.7.0/BUILD.bazel b/third_party/cargo/vendor/core-foundation-0.7.0/BUILD.bazel index c6201bc..59b6701 100644 --- a/third_party/cargo/vendor/core-foundation-0.7.0/BUILD.bazel +++ b/third_party/cargo/vendor/core-foundation-0.7.0/BUILD.bazel @@ -50,7 +50,7 @@ rust_library( # buildifier: leave-alone deps = [ "//third_party/cargo/vendor/core-foundation-sys-0.7.0:core_foundation_sys", - "//third_party/cargo/vendor/libc-0.2.71:libc", + "//third_party/cargo/vendor/libc-0.2.82:libc", ], ) diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/.cargo-checksum.json b/third_party/cargo/vendor/core-foundation-0.9.1/.cargo-checksum.json new file mode 100644 index 0000000..e0d209d --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"0ddd9a3c5e8b40befdd1dd5efdfc95cacff3d244ed472e413c19fc61c2e17697","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","src/array.rs":"221e81de15d95ca453df39466ba65faf879f2923202145958dfcebe63bfef97f","src/attributed_string.rs":"c04c5a3c912b6ab58d3081fa5dfa8fda07957b26396ebc907bba5ad07dc1087d","src/base.rs":"9ed46d59afdb22ecc65504ccd77f1c98108ea0ff96fad568dadb7ed49fde588c","src/boolean.rs":"f5b4d295aaf6cc3681212afebeae2974c5d551125badcc066e6089ac0d2a0873","src/bundle.rs":"7c26060c6ca64347b96800498e663d622f8dc1aa551a2f18cffa258cd27272a0","src/characterset.rs":"a3ffb46c5463c99813eebfc177a65794f44a1b9343534e28bbccd262034714c2","src/data.rs":"a1d7e6430c745731fc7b2aee49af9f14e79c8a288951c82ea6507689a3356af8","src/date.rs":"a02f6cca7b6e8fbabc7713177429012658dba5146556e14a08e7baaf81958d83","src/dictionary.rs":"ed8080eb00507e342521fb2c513a83c5706e883c3f8d67d8f38e9a0ed685c7eb","src/error.rs":"22c21087d9c2c103d1bcb2c4af33b684317bbda5d4747902e510d410f8c1a14b","src/filedescriptor.rs":"6c2087a8e101bfb31a6b916759a69a82852b18b2174c818f6ec9211ccdcaf1e6","src/lib.rs":"867b9b5acbc8dcf1d9f61a936cec5c26762a0af444fa83cafdf9f3ab1ee979eb","src/number.rs":"5a6cc9036c156e7e9d787864dd671087677abf4175cd840cbf123ccd89abcafe","src/propertylist.rs":"9f182135d9eb21421673280112d5676051bf7f1c2548c6da1ff879ea0bfb4704","src/runloop.rs":"048772c566cf3a1ec3e478958293aa9f3af38ff40b71ab7695f86b61d12f2023","src/set.rs":"da75b31f894bd04c0518211e113ca21a2781cd6ac71018104eeb354dd2f1a19e","src/string.rs":"bea7f3fd2528377442d1bebfeacf7e905d879320ae662fe6a8ef917b6a8e9c36","src/timezone.rs":"6dcf188db76303292b519d6283b71b71c7b3d6ed1afddc28de16d727075f5ef1","src/url.rs":"c544725399d3fbc4de54fd9d1c987e02f81760effd08c5c64c8deacd11478950","src/uuid.rs":"c3457e43fc22ba0f3fcab3ee8108500585ba005dbcbfa7edad0d389701ddf379","tests/use_macro_outside_crate.rs":"ed5e74ac9e988f2609c0b785189f1e6368d693f6401603ad065521f3ab51df94"},"package":"0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/BUILD.bazel b/third_party/cargo/vendor/core-foundation-0.9.1/BUILD.bazel new file mode 100644 index 0000000..f7f36f2 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/BUILD.bazel @@ -0,0 +1,57 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "core_foundation", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.9.1", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/core-foundation-sys-0.8.2:core_foundation_sys", + "//third_party/cargo/vendor/libc-0.2.82:libc", + ], +) + +# Unsupported target "use_macro_outside_crate" with type "test" omitted diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/Cargo.toml b/third_party/cargo/vendor/core-foundation-0.9.1/Cargo.toml new file mode 100644 index 0000000..66aabee --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/Cargo.toml @@ -0,0 +1,43 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-foundation" +version = "0.9.1" +authors = ["The Servo Project Developers"] +description = "Bindings to Core Foundation for macOS" +homepage = "https://github.com/servo/core-foundation-rs" +keywords = ["macos", "framework", "objc"] +categories = ["os::macos-apis"] +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" +[dependencies.chrono] +version = "0.4" +optional = true + +[dependencies.core-foundation-sys] +version = "0.8.0" + +[dependencies.libc] +version = "0.2" + +[dependencies.uuid] +version = "0.5" +optional = true + +[features] +mac_os_10_7_support = ["core-foundation-sys/mac_os_10_7_support"] +mac_os_10_8_features = ["core-foundation-sys/mac_os_10_8_features"] +with-chrono = ["chrono"] +with-uuid = ["uuid"] diff --git a/third_party/cargo/vendor/cocoa-0.20.1/LICENSE-APACHE b/third_party/cargo/vendor/core-foundation-0.9.1/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/cocoa-0.20.1/LICENSE-APACHE rename to third_party/cargo/vendor/core-foundation-0.9.1/LICENSE-APACHE diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/LICENSE-MIT b/third_party/cargo/vendor/core-foundation-0.9.1/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/LICENSE-MIT rename to third_party/cargo/vendor/core-foundation-0.9.1/LICENSE-MIT diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/array.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/array.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/array.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/array.rs diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/attributed_string.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/attributed_string.rs new file mode 100644 index 0000000..d4a4679 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/attributed_string.rs @@ -0,0 +1,98 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use core_foundation_sys::attributed_string::*; + +use base::TCFType; +use core_foundation_sys::base::{CFIndex, CFRange, kCFAllocatorDefault}; +use std::ptr::null; +use string::{CFString, CFStringRef}; + +declare_TCFType!{ + CFAttributedString, CFAttributedStringRef +} +impl_TCFType!(CFAttributedString, CFAttributedStringRef, CFAttributedStringGetTypeID); + +impl CFAttributedString { + #[inline] + pub fn new(string: &CFString) -> Self { + unsafe { + let astr_ref = CFAttributedStringCreate( + kCFAllocatorDefault, string.as_concrete_TypeRef(), null()); + + CFAttributedString::wrap_under_create_rule(astr_ref) + } + } + + #[inline] + pub fn char_len(&self) -> CFIndex { + unsafe { + CFAttributedStringGetLength(self.0) + } + } +} + +declare_TCFType!{ + CFMutableAttributedString, CFMutableAttributedStringRef +} +impl_TCFType!(CFMutableAttributedString, CFMutableAttributedStringRef, CFAttributedStringGetTypeID); + +impl CFMutableAttributedString { + #[inline] + pub fn new() -> Self { + unsafe { + let astr_ref = CFAttributedStringCreateMutable( + kCFAllocatorDefault, 0); + + CFMutableAttributedString::wrap_under_create_rule(astr_ref) + } + } + + #[inline] + pub fn char_len(&self) -> CFIndex { + unsafe { + CFAttributedStringGetLength(self.0) + } + } + + #[inline] + pub fn replace_str(&mut self, string: &CFString, range: CFRange) { + unsafe { + CFAttributedStringReplaceString( + self.0, range, string.as_concrete_TypeRef()); + } + } + + #[inline] + pub fn set_attribute(&mut self, range: CFRange, name: CFStringRef, value: &T) { + unsafe { + CFAttributedStringSetAttribute( + self.0, range, name, value.as_CFTypeRef()); + } + } +} + +impl Default for CFMutableAttributedString { + fn default() -> Self { + Self::new() + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn attributed_string_type_id_comparison() { + // CFMutableAttributedString TypeID must be equal to CFAttributedString TypeID. + // Compilation must not fail. + assert_eq!(::type_id(), ::type_id()); + } +} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/base.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/base.rs new file mode 100644 index 0000000..f08f2b2 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/base.rs @@ -0,0 +1,452 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std; +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::mem::ManuallyDrop; +use std::ops::{Deref, DerefMut}; +use std::os::raw::c_void; + +pub use core_foundation_sys::base::*; + +use string::CFString; +use ConcreteCFType; + +pub trait CFIndexConvertible { + /// Always use this method to construct a `CFIndex` value. It performs bounds checking to + /// ensure the value is in range. + fn to_CFIndex(self) -> CFIndex; +} + +impl CFIndexConvertible for usize { + #[inline] + fn to_CFIndex(self) -> CFIndex { + let max_CFIndex = CFIndex::max_value(); + if self > (max_CFIndex as usize) { + panic!("value out of range") + } + self as CFIndex + } +} + +declare_TCFType!{ + /// Superclass of all Core Foundation objects. + CFType, CFTypeRef +} + +impl CFType { + /// Try to downcast the `CFType` to a subclass. Checking if the instance is the + /// correct subclass happens at runtime and `None` is returned if it is not the correct type. + /// Works similar to [`Box::downcast`] and [`CFPropertyList::downcast`]. + /// + /// # Examples + /// + /// ``` + /// # use core_foundation::string::CFString; + /// # use core_foundation::boolean::CFBoolean; + /// # use core_foundation::base::{CFType, TCFType}; + /// # + /// // Create a string. + /// let string: CFString = CFString::from_static_string("FooBar"); + /// // Cast it up to a CFType. + /// let cf_type: CFType = string.as_CFType(); + /// // Cast it down again. + /// assert_eq!(cf_type.downcast::().unwrap().to_string(), "FooBar"); + /// // Casting it to some other type will yield `None` + /// assert!(cf_type.downcast::().is_none()); + /// ``` + /// + /// ```compile_fail + /// # use core_foundation::array::CFArray; + /// # use core_foundation::base::TCFType; + /// # use core_foundation::boolean::CFBoolean; + /// # use core_foundation::string::CFString; + /// # + /// let boolean_array = CFArray::from_CFTypes(&[CFBoolean::true_value()]).into_CFType(); + /// + /// // This downcast is not allowed and causes compiler error, since it would cause undefined + /// // behavior to access the elements of the array as a CFString: + /// let invalid_string_array = boolean_array + /// .downcast_into::>() + /// .unwrap(); + /// ``` + /// + /// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast + /// [`CFPropertyList::downcast`]: ../propertylist/struct.CFPropertyList.html#method.downcast + #[inline] + pub fn downcast(&self) -> Option { + if self.instance_of::() { + unsafe { + let reference = T::Ref::from_void_ptr(self.0); + Some(T::wrap_under_get_rule(reference)) + } + } else { + None + } + } + + /// Similar to [`downcast`], but consumes self and can thus avoid touching the retain count. + /// + /// [`downcast`]: #method.downcast + #[inline] + pub fn downcast_into(self) -> Option { + if self.instance_of::() { + unsafe { + let reference = T::Ref::from_void_ptr(self.0); + mem::forget(self); + Some(T::wrap_under_create_rule(reference)) + } + } else { + None + } + } +} + +impl fmt::Debug for CFType { + /// Formats the value using [`CFCopyDescription`]. + /// + /// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let desc = unsafe { + CFString::wrap_under_create_rule(CFCopyDescription(self.0)) + }; + desc.fmt(f) + } +} + +impl Clone for CFType { + #[inline] + fn clone(&self) -> CFType { + unsafe { + TCFType::wrap_under_get_rule(self.0) + } + } +} + +impl PartialEq for CFType { + #[inline] + fn eq(&self, other: &CFType) -> bool { + unsafe { + CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 + } + } +} + +declare_TCFType!(CFAllocator, CFAllocatorRef); +impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID); + +impl CFAllocator { + #[inline] + pub fn new(mut context: CFAllocatorContext) -> CFAllocator { + unsafe { + let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context); + TCFType::wrap_under_create_rule(allocator_ref) + } + } +} + + +/// All Core Foundation types implement this trait. The associated type `Ref` specifies the +/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is +/// `CFArrayRef`. +/// +/// Most structs that implement this trait will do so via the [`impl_TCFType`] macro. +/// +/// [`impl_TCFType`]: ../macro.impl_TCFType.html +pub trait TCFType { + /// The reference type wrapped inside this type. + type Ref: TCFTypeRef; + + /// Returns the object as its concrete TypeRef. + fn as_concrete_TypeRef(&self) -> Self::Ref; + + /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this + /// when following Core Foundation's "Create Rule". The reference count is *not* bumped. + unsafe fn wrap_under_create_rule(obj: Self::Ref) -> Self; + + /// Returns the type ID for this class. + fn type_id() -> CFTypeID; + + /// Returns the object as a wrapped `CFType`. The reference count is incremented by one. + #[inline] + fn as_CFType(&self) -> CFType { + unsafe { + TCFType::wrap_under_get_rule(self.as_CFTypeRef()) + } + } + + /// Returns the object as a wrapped `CFType`. Consumes self and avoids changing the reference + /// count. + #[inline] + fn into_CFType(self) -> CFType + where + Self: Sized, + { + let reference = self.as_CFTypeRef(); + mem::forget(self); + unsafe { TCFType::wrap_under_create_rule(reference) } + } + + /// Returns the object as a raw `CFTypeRef`. The reference count is not adjusted. + fn as_CFTypeRef(&self) -> CFTypeRef; + + /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this + /// when following Core Foundation's "Get Rule". The reference count *is* bumped. + unsafe fn wrap_under_get_rule(reference: Self::Ref) -> Self; + + /// Returns the reference count of the object. It is unwise to do anything other than test + /// whether the return value of this method is greater than zero. + #[inline] + fn retain_count(&self) -> CFIndex { + unsafe { + CFGetRetainCount(self.as_CFTypeRef()) + } + } + + /// Returns the type ID of this object. + #[inline] + fn type_of(&self) -> CFTypeID { + unsafe { + CFGetTypeID(self.as_CFTypeRef()) + } + } + + /// Writes a debugging version of this object on standard error. + fn show(&self) { + unsafe { + CFShow(self.as_CFTypeRef()) + } + } + + /// Returns true if this value is an instance of another type. + #[inline] + fn instance_of(&self) -> bool { + self.type_of() == OtherCFType::type_id() + } +} + +impl TCFType for CFType { + type Ref = CFTypeRef; + + #[inline] + fn as_concrete_TypeRef(&self) -> CFTypeRef { + self.0 + } + + #[inline] + unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType { + assert!(!reference.is_null(), "Attempted to create a NULL object."); + let reference: CFTypeRef = CFRetain(reference); + TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> CFTypeRef { + self.as_concrete_TypeRef() + } + + #[inline] + unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType { + assert!(!obj.is_null(), "Attempted to create a NULL object."); + CFType(obj) + } + + #[inline] + fn type_id() -> CFTypeID { + // FIXME(pcwalton): Is this right? + 0 + } +} + +/// A reference to an element inside a container +pub struct ItemRef<'a, T: 'a>(ManuallyDrop, PhantomData<&'a T>); + +impl<'a, T> Deref for ItemRef<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for ItemRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.0.fmt(f) + } +} + +impl<'a, T: PartialEq> PartialEq for ItemRef<'a, T> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +/// A reference to a mutable element inside a container +pub struct ItemMutRef<'a, T: 'a>(ManuallyDrop, PhantomData<&'a T>); + +impl<'a, T> Deref for ItemMutRef<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<'a, T> DerefMut for ItemMutRef<'a, T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for ItemMutRef<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.0.fmt(f) + } +} + +impl<'a, T: PartialEq> PartialEq for ItemMutRef<'a, T> { + fn eq(&self, other: &Self) -> bool { + self.0.eq(&other.0) + } +} + +/// A trait describing how to convert from the stored *mut c_void to the desired T +pub unsafe trait FromMutVoid { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> where Self: std::marker::Sized; +} + +unsafe impl FromMutVoid for u32 { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { + ItemMutRef(ManuallyDrop::new(x as u32), PhantomData) + } +} + +unsafe impl FromMutVoid for *const c_void { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { + ItemMutRef(ManuallyDrop::new(x), PhantomData) + } +} + +unsafe impl FromMutVoid for T { + unsafe fn from_mut_void<'a>(x: *mut c_void) -> ItemMutRef<'a, Self> { + ItemMutRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) + } +} + +/// A trait describing how to convert from the stored *const c_void to the desired T +pub unsafe trait FromVoid { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> where Self: std::marker::Sized; +} + +unsafe impl FromVoid for u32 { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { + // Functions like CGFontCopyTableTags treat the void*'s as u32's + // so we convert by casting directly + ItemRef(ManuallyDrop::new(x as u32), PhantomData) + } +} + +unsafe impl FromVoid for *const c_void { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { + ItemRef(ManuallyDrop::new(x), PhantomData) + } +} + +unsafe impl FromVoid for T { + unsafe fn from_void<'a>(x: *const c_void) -> ItemRef<'a, Self> { + ItemRef(ManuallyDrop::new(TCFType::wrap_under_create_rule(T::Ref::from_void_ptr(x))), PhantomData) + } +} + +/// A trait describing how to convert from the stored *const c_void to the desired T +pub unsafe trait ToVoid { + fn to_void(&self) -> *const c_void; +} + +unsafe impl ToVoid<*const c_void> for *const c_void { + fn to_void(&self) -> *const c_void { + *self + } +} + +unsafe impl<'a> ToVoid for &'a CFType { + fn to_void(&self) -> *const ::std::os::raw::c_void { + self.as_concrete_TypeRef().as_void_ptr() + } +} + +unsafe impl ToVoid for CFType { + fn to_void(&self) -> *const ::std::os::raw::c_void { + self.as_concrete_TypeRef().as_void_ptr() + } +} + +unsafe impl ToVoid for CFTypeRef { + fn to_void(&self) -> *const ::std::os::raw::c_void { + self.as_void_ptr() + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use std::mem; + use boolean::CFBoolean; + + #[test] + fn cftype_instance_of() { + let string = CFString::from_static_string("foo"); + let cftype = string.as_CFType(); + + assert!(cftype.instance_of::()); + assert!(!cftype.instance_of::()); + } + + #[test] + fn as_cftype_retain_count() { + let string = CFString::from_static_string("bar"); + assert_eq!(string.retain_count(), 1); + let cftype = string.as_CFType(); + assert_eq!(cftype.retain_count(), 2); + mem::drop(string); + assert_eq!(cftype.retain_count(), 1); + } + + #[test] + fn into_cftype_retain_count() { + let string = CFString::from_static_string("bar"); + assert_eq!(string.retain_count(), 1); + let cftype = string.into_CFType(); + assert_eq!(cftype.retain_count(), 1); + } + + #[test] + fn as_cftype_and_downcast() { + let string = CFString::from_static_string("bar"); + let cftype = string.as_CFType(); + let string2 = cftype.downcast::().unwrap(); + assert_eq!(string2.to_string(), "bar"); + + assert_eq!(string.retain_count(), 3); + assert_eq!(cftype.retain_count(), 3); + assert_eq!(string2.retain_count(), 3); + } + + #[test] + fn into_cftype_and_downcast_into() { + let string = CFString::from_static_string("bar"); + let cftype = string.into_CFType(); + let string2 = cftype.downcast_into::().unwrap(); + assert_eq!(string2.to_string(), "bar"); + assert_eq!(string2.retain_count(), 1); + } +} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/boolean.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/boolean.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/boolean.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/boolean.rs diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/bundle.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/bundle.rs new file mode 100644 index 0000000..e79e3c3 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/bundle.rs @@ -0,0 +1,172 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation Bundle Type + +use core_foundation_sys::base::kCFAllocatorDefault; +pub use core_foundation_sys::bundle::*; +use core_foundation_sys::url::kCFURLPOSIXPathStyle; +use std::path::PathBuf; + +use base::{CFType, TCFType}; +use url::CFURL; +use dictionary::CFDictionary; +use std::os::raw::c_void; +use string::CFString; + +declare_TCFType!{ + /// A Bundle type. + CFBundle, CFBundleRef +} +impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID); + +impl CFBundle { + pub fn new(bundleURL: CFURL) -> Option { + unsafe { + let bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundleURL.as_concrete_TypeRef()); + if bundle_ref.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(bundle_ref)) + } + } + } + + pub fn bundle_with_identifier(identifier: CFString) -> Option { + unsafe { + let bundle_ref = CFBundleGetBundleWithIdentifier(identifier.as_concrete_TypeRef()); + if bundle_ref.is_null() { + None + } else { + Some(TCFType::wrap_under_get_rule(bundle_ref)) + } + } + } + + pub fn function_pointer_for_name(&self, function_name: CFString) -> *const c_void { + unsafe { + CFBundleGetFunctionPointerForName(self.as_concrete_TypeRef(), + function_name.as_concrete_TypeRef()) + } + } + + pub fn main_bundle() -> CFBundle { + unsafe { + let bundle_ref = CFBundleGetMainBundle(); + TCFType::wrap_under_get_rule(bundle_ref) + } + } + + pub fn info_dictionary(&self) -> CFDictionary { + unsafe { + let info_dictionary = CFBundleGetInfoDictionary(self.0); + TCFType::wrap_under_get_rule(info_dictionary) + } + } + + pub fn executable_url(&self) -> Option { + unsafe { + let exe_url = CFBundleCopyExecutableURL(self.0); + if exe_url.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(exe_url)) + } + } + } + + /// Bundle's own location + pub fn bundle_url(&self) -> Option { + unsafe { + let bundle_url = CFBundleCopyBundleURL(self.0); + if bundle_url.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(bundle_url)) + } + } + } + + /// Bundle's own location + pub fn path(&self) -> Option { + let url = self.bundle_url()?; + Some(PathBuf::from(url.get_file_system_path(kCFURLPOSIXPathStyle).to_string())) + } + + pub fn private_frameworks_url(&self) -> Option { + unsafe { + let fw_url = CFBundleCopyPrivateFrameworksURL(self.0); + if fw_url.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(fw_url)) + } + } + } + + pub fn shared_support_url(&self) -> Option { + unsafe { + let fw_url = CFBundleCopySharedSupportURL(self.0); + if fw_url.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(fw_url)) + } + } + } +} + + +#[test] +fn safari_executable_url() { + use string::CFString; + use url::{CFURL, kCFURLPOSIXPathStyle}; + + let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); + let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + let cfurl_executable = CFBundle::new(cfurl_path) + .expect("Safari not present") + .executable_url(); + assert!(cfurl_executable.is_some()); + assert_eq!(cfurl_executable + .unwrap() + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + "/Applications/Safari.app/Contents/MacOS/Safari"); +} + +#[test] +fn safari_private_frameworks_url() { + use string::CFString; + use url::{CFURL, kCFURLPOSIXPathStyle}; + + let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); + let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + let cfurl_executable = CFBundle::new(cfurl_path) + .expect("Safari not present") + .private_frameworks_url(); + assert!(cfurl_executable.is_some()); + assert_eq!(cfurl_executable + .unwrap() + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + "/Applications/Safari.app/Contents/Frameworks"); +} + +#[test] +fn non_existant_bundle() { + use string::CFString; + use url::{CFURL, kCFURLPOSIXPathStyle}; + + let cfstr_path = CFString::from_static_string("/usr/local/foo"); + let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + assert!(CFBundle::new(cfurl_path).is_none()); +} diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/characterset.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/characterset.rs new file mode 100644 index 0000000..d1b9439 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/characterset.rs @@ -0,0 +1,21 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A set of Unicode compliant characters. + +pub use core_foundation_sys::characterset::*; + +use base::TCFType; + +declare_TCFType!{ + /// An immutable set of Unicde characters. + CFCharacterSet, CFCharacterSetRef +} +impl_TCFType!(CFCharacterSet, CFCharacterSetRef, CFCharacterSetGetTypeID); +impl_CFTypeDescription!(CFCharacterSet); diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/data.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/data.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/data.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/data.rs diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/date.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/date.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/date.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/date.rs diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/dictionary.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/dictionary.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/dictionary.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/dictionary.rs diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/error.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/error.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/error.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/error.rs diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/filedescriptor.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/filedescriptor.rs similarity index 96% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/filedescriptor.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/filedescriptor.rs index 2c999b5..061bd2d 100644 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/filedescriptor.rs +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/filedescriptor.rs @@ -15,7 +15,7 @@ use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; use base::TCFType; use runloop::CFRunLoopSource; -use std::mem; +use std::mem::MaybeUninit; use std::os::unix::io::{AsRawFd, RawFd}; use std::ptr; @@ -46,9 +46,9 @@ impl CFFileDescriptor { pub fn context(&self) -> CFFileDescriptorContext { unsafe { - let mut context: CFFileDescriptorContext = mem::uninitialized(); - CFFileDescriptorGetContext(self.0, &mut context); - context + let mut context = MaybeUninit::::uninit(); + CFFileDescriptorGetContext(self.0, context.as_mut_ptr()); + context.assume_init() } } diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/lib.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/lib.rs new file mode 100644 index 0000000..eaab9a0 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/lib.rs @@ -0,0 +1,235 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_snake_case)] + +//! This crate provides wrappers around the underlying CoreFoundation +//! types and functions that are available on Apple's operating systems. +//! +//! It also provides a framework for other crates to use when wrapping +//! other frameworks that use the CoreFoundation framework. + +extern crate core_foundation_sys; +extern crate libc; + +#[cfg(feature = "with-chrono")] +extern crate chrono; + +use base::TCFType; + +pub unsafe trait ConcreteCFType: TCFType {} + +/// Declare a Rust type that wraps an underlying CoreFoundation type. +/// +/// This will provide an implementation of `Drop` using [`CFRelease`]. +/// The type must have an implementation of the [`TCFType`] trait, usually +/// provided using the [`impl_TCFType`] macro. +/// +/// ``` +/// #[macro_use] extern crate core_foundation; +/// // Make sure that the `TCFType` trait is in scope. +/// use core_foundation::base::{CFTypeID, TCFType}; +/// +/// extern "C" { +/// // We need a function that returns the `CFTypeID`. +/// pub fn ShrubberyGetTypeID() -> CFTypeID; +/// } +/// +/// pub struct __Shrubbery {} +/// // The ref type must be a pointer to the underlying struct. +/// pub type ShrubberyRef = *const __Shrubbery; +/// +/// declare_TCFType!(Shrubbery, ShrubberyRef); +/// impl_TCFType!(Shrubbery, ShrubberyRef, ShrubberyGetTypeID); +/// # fn main() {} +/// ``` +/// +/// [`CFRelease`]: https://developer.apple.com/documentation/corefoundation/1521153-cfrelease +/// [`TCFType`]: base/trait.TCFType.html +/// [`impl_TCFType`]: macro.impl_TCFType.html +#[macro_export] +macro_rules! declare_TCFType { + ( + $(#[$doc:meta])* + $ty:ident, $raw:ident + ) => { + $(#[$doc])* + pub struct $ty($raw); + + impl Drop for $ty { + fn drop(&mut self) { + unsafe { $crate::base::CFRelease(self.as_CFTypeRef()) } + } + } + } +} + +/// Provide an implementation of the [`TCFType`] trait for the Rust +/// wrapper type around an underlying CoreFoundation type. +/// +/// See [`declare_TCFType`] for details. +/// +/// [`declare_TCFType`]: macro.declare_TCFType.html +/// [`TCFType`]: base/trait.TCFType.html +#[macro_export] +macro_rules! impl_TCFType { + ($ty:ident, $ty_ref:ident, $ty_id:ident) => { + impl_TCFType!($ty<>, $ty_ref, $ty_id); + unsafe impl $crate::ConcreteCFType for $ty { } + }; + + ($ty:ident<$($p:ident $(: $bound:path)*),*>, $ty_ref:ident, $ty_id:ident) => { + impl<$($p $(: $bound)*),*> $crate::base::TCFType for $ty<$($p),*> { + type Ref = $ty_ref; + + #[inline] + fn as_concrete_TypeRef(&self) -> $ty_ref { + self.0 + } + + #[inline] + unsafe fn wrap_under_get_rule(reference: $ty_ref) -> Self { + assert!(!reference.is_null(), "Attempted to create a NULL object."); + let reference = $crate::base::CFRetain(reference as *const ::std::os::raw::c_void) as $ty_ref; + $crate::base::TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> $crate::base::CFTypeRef { + self.as_concrete_TypeRef() as $crate::base::CFTypeRef + } + + #[inline] + unsafe fn wrap_under_create_rule(reference: $ty_ref) -> Self { + assert!(!reference.is_null(), "Attempted to create a NULL object."); + // we need one PhantomData for each type parameter so call ourselves + // again with @Phantom $p to produce that + $ty(reference $(, impl_TCFType!(@Phantom $p))*) + } + + #[inline] + fn type_id() -> $crate::base::CFTypeID { + unsafe { + $ty_id() + } + } + } + + impl Clone for $ty { + #[inline] + fn clone(&self) -> $ty { + unsafe { + $ty::wrap_under_get_rule(self.0) + } + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, other: &$ty) -> bool { + self.as_CFType().eq(&other.as_CFType()) + } + } + + impl Eq for $ty { } + + unsafe impl<'a> $crate::base::ToVoid<$ty> for &'a $ty { + fn to_void(&self) -> *const ::std::os::raw::c_void { + use $crate::base::TCFTypeRef; + self.as_concrete_TypeRef().as_void_ptr() + } + } + + unsafe impl $crate::base::ToVoid<$ty> for $ty { + fn to_void(&self) -> *const ::std::os::raw::c_void { + use $crate::base::TCFTypeRef; + self.as_concrete_TypeRef().as_void_ptr() + } + } + + unsafe impl $crate::base::ToVoid<$ty> for $ty_ref { + fn to_void(&self) -> *const ::std::os::raw::c_void { + use $crate::base::TCFTypeRef; + self.as_void_ptr() + } + } + + }; + + (@Phantom $x:ident) => { ::std::marker::PhantomData }; +} + + +/// Implement `std::fmt::Debug` for the given type. +/// +/// This will invoke the implementation of `Debug` for [`CFType`] +/// which invokes [`CFCopyDescription`]. +/// +/// The type must have an implementation of the [`TCFType`] trait, usually +/// provided using the [`impl_TCFType`] macro. +/// +/// [`CFType`]: base/struct.CFType.html#impl-Debug +/// [`CFCopyDescription`]: https://developer.apple.com/documentation/corefoundation/1521252-cfcopydescription?language=objc +/// [`TCFType`]: base/trait.TCFType.html +/// [`impl_TCFType`]: macro.impl_TCFType.html +#[macro_export] +macro_rules! impl_CFTypeDescription { + ($ty:ident) => { + // it's fine to use an empty <> list + impl_CFTypeDescription!($ty<>); + }; + ($ty:ident<$($p:ident $(: $bound:path)*),*>) => { + impl<$($p $(: $bound)*),*> ::std::fmt::Debug for $ty<$($p),*> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.as_CFType().fmt(f) + } + } + } +} + +#[macro_export] +macro_rules! impl_CFComparison { + ($ty:ident, $compare:ident) => { + impl PartialOrd for $ty { + #[inline] + fn partial_cmp(&self, other: &$ty) -> Option<::std::cmp::Ordering> { + unsafe { + Some($compare(self.as_concrete_TypeRef(), other.as_concrete_TypeRef(), ::std::ptr::null_mut()).into()) + } + } + } + + impl Ord for $ty { + #[inline] + fn cmp(&self, other: &$ty) -> ::std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } + } + } +} + +pub mod array; +pub mod attributed_string; +pub mod base; +pub mod boolean; +pub mod characterset; +pub mod data; +pub mod date; +pub mod dictionary; +pub mod error; +pub mod filedescriptor; +pub mod number; +pub mod set; +pub mod string; +pub mod url; +pub mod bundle; +pub mod propertylist; +pub mod runloop; +pub mod timezone; +pub mod uuid; diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/number.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/number.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/number.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/number.rs diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/propertylist.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/propertylist.rs similarity index 98% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/propertylist.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/propertylist.rs index 14ae173..9f34f56 100644 --- a/third_party/cargo/vendor/core-foundation-0.6.4/src/propertylist.rs +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/propertylist.rs @@ -121,6 +121,7 @@ impl CFPropertyList { #[inline] pub unsafe fn wrap_under_get_rule(reference: CFPropertyListRef) -> CFPropertyList { + assert!(!reference.is_null(), "Attempted to create a NULL object."); let reference = CFRetain(reference); CFPropertyList(reference) } @@ -147,6 +148,7 @@ impl CFPropertyList { #[inline] pub unsafe fn wrap_under_create_rule(obj: CFPropertyListRef) -> CFPropertyList { + assert!(!obj.is_null(), "Attempted to create a NULL object."); CFPropertyList(obj) } @@ -262,7 +264,7 @@ pub mod test { let boo = CFString::from_static_string("Boo"); let foo = CFString::from_static_string("Foo"); let tru = CFBoolean::true_value(); - let n42 = CFNumber::from(42); + let n42 = CFNumber::from(1i64<<33); let dict1 = CFDictionary::from_CFType_pairs(&[(bar.as_CFType(), boo.as_CFType()), (baz.as_CFType(), tru.as_CFType()), diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/runloop.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/runloop.rs new file mode 100644 index 0000000..5b27028 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/runloop.rs @@ -0,0 +1,198 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +pub use core_foundation_sys::runloop::*; +use core_foundation_sys::base::CFIndex; +use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; +use core_foundation_sys::string::CFStringRef; + +use base::{TCFType}; +use date::{CFAbsoluteTime, CFTimeInterval}; +use filedescriptor::CFFileDescriptor; +use string::{CFString}; + +pub type CFRunLoopMode = CFStringRef; + + +declare_TCFType!(CFRunLoop, CFRunLoopRef); +impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); +impl_CFTypeDescription!(CFRunLoop); + +impl CFRunLoop { + pub fn get_current() -> CFRunLoop { + unsafe { + let run_loop_ref = CFRunLoopGetCurrent(); + TCFType::wrap_under_get_rule(run_loop_ref) + } + } + + pub fn get_main() -> CFRunLoop { + unsafe { + let run_loop_ref = CFRunLoopGetMain(); + TCFType::wrap_under_get_rule(run_loop_ref) + } + } + + pub fn run_current() { + unsafe { + CFRunLoopRun(); + } + } + + pub fn stop(&self) { + unsafe { + CFRunLoopStop(self.0); + } + } + + pub fn current_mode(&self) -> Option { + unsafe { + let string_ref = CFRunLoopCopyCurrentMode(self.0); + if string_ref.is_null() { + return None; + } + + let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref); + Some(cf_string.to_string()) + } + } + + pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 + } + } + + pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddTimer(self.0, timer.0, mode); + } + } + + pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveTimer(self.0, timer.0, mode); + } + } + + pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsSource(self.0, source.0, mode) != 0 + } + } + + pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddSource(self.0, source.0, mode); + } + } + + pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveSource(self.0, source.0, mode); + } + } + + pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 + } + } + + pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddObserver(self.0, observer.0, mode); + } + } + + pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveObserver(self.0, observer.0, mode); + } + } + +} + + +declare_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef); +impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); + +impl CFRunLoopTimer { + pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { + unsafe { + let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context); + TCFType::wrap_under_create_rule(timer_ref) + } + } +} + + +declare_TCFType!(CFRunLoopSource, CFRunLoopSourceRef); +impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); + +impl CFRunLoopSource { + pub fn from_file_descriptor(fd: &CFFileDescriptor, order: CFIndex) -> Option { + fd.to_run_loop_source(order) + } +} + +declare_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef); +impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID); + +#[cfg(test)] +mod test { + use super::*; + use date::{CFDate, CFAbsoluteTime}; + use std::mem; + use std::os::raw::c_void; + use std::sync::mpsc; + + #[test] + fn wait_200_milliseconds() { + let run_loop = CFRunLoop::get_current(); + + let now = CFDate::now().abs_time(); + let (elapsed_tx, elapsed_rx) = mpsc::channel(); + let mut info = Info { + start_time: now, + elapsed_tx, + }; + let mut context = CFRunLoopTimerContext { + version: 0, + info: &mut info as *mut _ as *mut c_void, + retain: None, + release: None, + copyDescription: None, + }; + + let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); + unsafe { + run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); + } + CFRunLoop::run_current(); + let elapsed = elapsed_rx.try_recv().unwrap(); + println!("wait_200_milliseconds, elapsed: {}", elapsed); + assert!(elapsed > 0.19 && elapsed < 0.30); + } + + struct Info { + start_time: CFAbsoluteTime, + elapsed_tx: mpsc::Sender, + } + + extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, raw_info: *mut c_void) { + let info: *mut Info = unsafe { mem::transmute(raw_info) }; + let now = CFDate::now().abs_time(); + let elapsed = now - unsafe { (*info).start_time }; + let _ = unsafe { (*info).elapsed_tx.send(elapsed) }; + CFRunLoop::get_current().stop(); + } +} diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/set.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/set.rs new file mode 100644 index 0000000..eb1d357 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/set.rs @@ -0,0 +1,53 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An immutable bag of elements. + +pub use core_foundation_sys::set::*; +use core_foundation_sys::base::{CFTypeRef, CFRelease, kCFAllocatorDefault}; + +use base::{CFIndexConvertible, TCFType}; + +use std::os::raw::c_void; +use std::marker::PhantomData; + +/// An immutable bag of elements. +pub struct CFSet(CFSetRef, PhantomData); + +impl Drop for CFSet { + fn drop(&mut self) { + unsafe { CFRelease(self.as_CFTypeRef()) } + } +} + +impl_TCFType!(CFSet, CFSetRef, CFSetGetTypeID); +impl_CFTypeDescription!(CFSet); + +impl CFSet { + /// Creates a new set from a list of `CFType` instances. + pub fn from_slice(elems: &[T]) -> CFSet where T: TCFType { + unsafe { + let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); + let set_ref = CFSetCreate(kCFAllocatorDefault, + elems.as_ptr(), + elems.len().to_CFIndex(), + &kCFTypeSetCallBacks); + TCFType::wrap_under_create_rule(set_ref) + } + } +} + +impl CFSet { + /// Get the number of elements in the CFSet + pub fn len(&self) -> usize { + unsafe { + CFSetGetCount(self.0) as usize + } + } +} diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/string.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/string.rs new file mode 100644 index 0000000..3f5994b --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/string.rs @@ -0,0 +1,197 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Immutable strings. + +pub use core_foundation_sys::string::*; + +use base::{CFIndexConvertible, TCFType}; + +use core_foundation_sys::base::{Boolean, CFIndex, CFRange}; +use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull}; +use std::borrow::Cow; +use std::fmt; +use std::str::{self, FromStr}; +use std::ptr; +use std::ffi::CStr; + + +declare_TCFType!{ + /// An immutable string in one of a variety of encodings. + CFString, CFStringRef +} +impl_TCFType!(CFString, CFStringRef, CFStringGetTypeID); + +impl FromStr for CFString { + type Err = (); + + /// See also CFString::new for a variant of this which does not return a Result + #[inline] + fn from_str(string: &str) -> Result { + Ok(CFString::new(string)) + } +} + +impl<'a> From<&'a str> for CFString { + #[inline] + fn from(string: &'a str) -> CFString { + CFString::new(string) + } +} + +impl<'a> From<&'a CFString> for Cow<'a, str> { + fn from(cf_str: &'a CFString) -> Cow<'a, str> { + unsafe { + // Do this without allocating if we can get away with it + let c_string = CFStringGetCStringPtr(cf_str.0, kCFStringEncodingUTF8); + if !c_string.is_null() { + let c_str = CStr::from_ptr(c_string); + Cow::Borrowed(str::from_utf8_unchecked(c_str.to_bytes())) + } else { + let char_len = cf_str.char_len(); + + // First, ask how big the buffer ought to be. + let mut bytes_required: CFIndex = 0; + CFStringGetBytes(cf_str.0, + CFRange { location: 0, length: char_len }, + kCFStringEncodingUTF8, + 0, + false as Boolean, + ptr::null_mut(), + 0, + &mut bytes_required); + + // Then, allocate the buffer and actually copy. + let mut buffer = vec![b'\x00'; bytes_required as usize]; + + let mut bytes_used: CFIndex = 0; + let chars_written = CFStringGetBytes(cf_str.0, + CFRange { location: 0, length: char_len }, + kCFStringEncodingUTF8, + 0, + false as Boolean, + buffer.as_mut_ptr(), + buffer.len().to_CFIndex(), + &mut bytes_used); + assert_eq!(chars_written, char_len); + + // This is dangerous; we over-allocate and null-terminate the string (during + // initialization). + assert_eq!(bytes_used, buffer.len().to_CFIndex()); + Cow::Owned(String::from_utf8_unchecked(buffer)) + } + } + } +} + +impl fmt::Display for CFString { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(&Cow::from(self)) + } +} + +impl fmt::Debug for CFString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"{}\"", self) + } +} + + +impl CFString { + /// Creates a new `CFString` instance from a Rust string. + #[inline] + pub fn new(string: &str) -> CFString { + unsafe { + let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault, + string.as_ptr(), + string.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean); + CFString::wrap_under_create_rule(string_ref) + } + } + + /// Like `CFString::new`, but references a string that can be used as a backing store + /// by virtue of being statically allocated. + #[inline] + pub fn from_static_string(string: &'static str) -> CFString { + unsafe { + let string_ref = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, + string.as_ptr(), + string.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean, + kCFAllocatorNull); + TCFType::wrap_under_create_rule(string_ref) + } + } + + /// Returns the number of characters in the string. + #[inline] + pub fn char_len(&self) -> CFIndex { + unsafe { + CFStringGetLength(self.0) + } + } +} + +impl<'a> PartialEq<&'a str> for CFString { + fn eq(&self, other: &&str) -> bool { + unsafe { + let temp = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, + other.as_ptr(), + other.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean, + kCFAllocatorNull); + self.eq(&CFString::wrap_under_create_rule(temp)) + } + } +} + +impl<'a> PartialEq for &'a str { + #[inline] + fn eq(&self, other: &CFString) -> bool { + other.eq(self) + } +} + +impl PartialEq for String { + #[inline] + fn eq(&self, other: &CFString) -> bool { + other.eq(&self.as_str()) + } +} + +impl PartialEq for CFString { + #[inline] + fn eq(&self, other: &String) -> bool { + self.eq(&other.as_str()) + } +} + +#[test] +fn str_cmp() { + let cfstr = CFString::new("hello"); + assert_eq!("hello", cfstr); + assert_eq!(cfstr, "hello"); + assert_ne!(cfstr, "wrong"); + assert_ne!("wrong", cfstr); + let hello = String::from("hello"); + assert_eq!(hello, cfstr); + assert_eq!(cfstr, hello); +} + +#[test] +fn string_and_back() { + let original = "The quick brown fox jumped over the slow lazy dog."; + let cfstr = CFString::from_static_string(original); + let converted = cfstr.to_string(); + assert_eq!(converted, original); +} diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/timezone.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/timezone.rs new file mode 100644 index 0000000..a8bb2ed --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/timezone.rs @@ -0,0 +1,104 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation time zone objects. + +pub use core_foundation_sys::timezone::*; +use core_foundation_sys::base::kCFAllocatorDefault; + +use base::TCFType; +use date::{CFDate, CFTimeInterval}; +use string::CFString; + +#[cfg(feature = "with-chrono")] +use chrono::{FixedOffset, NaiveDateTime}; + + +declare_TCFType!{ + /// A time zone. + CFTimeZone, CFTimeZoneRef +} +impl_TCFType!(CFTimeZone, CFTimeZoneRef, CFTimeZoneGetTypeID); +impl_CFTypeDescription!(CFTimeZone); + +impl Default for CFTimeZone { + fn default() -> CFTimeZone { + unsafe { + let tz_ref = CFTimeZoneCopyDefault(); + TCFType::wrap_under_create_rule(tz_ref) + } + } +} + +impl CFTimeZone { + #[inline] + pub fn new(interval: CFTimeInterval) -> CFTimeZone { + unsafe { + let tz_ref = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, interval); + TCFType::wrap_under_create_rule(tz_ref) + } + } + + #[inline] + pub fn system() -> CFTimeZone { + unsafe { + let tz_ref = CFTimeZoneCopySystem(); + TCFType::wrap_under_create_rule(tz_ref) + } + } + + pub fn seconds_from_gmt(&self, date: CFDate) -> CFTimeInterval { + unsafe { + CFTimeZoneGetSecondsFromGMT(self.0, date.abs_time()) + } + } + + #[cfg(feature = "with-chrono")] + pub fn offset_at_date(&self, date: NaiveDateTime) -> FixedOffset { + let date = CFDate::from_naive_utc(date); + FixedOffset::east(self.seconds_from_gmt(date) as i32) + } + + #[cfg(feature = "with-chrono")] + pub fn from_offset(offset: FixedOffset) -> CFTimeZone { + CFTimeZone::new(offset.local_minus_utc() as f64) + } + + /// The timezone database ID that identifies the time zone. E.g. "America/Los_Angeles" or + /// "Europe/Paris". + pub fn name(&self) -> CFString { + unsafe { + CFString::wrap_under_get_rule(CFTimeZoneGetName(self.0)) + } + } +} + +#[cfg(test)] +mod test { + use super::CFTimeZone; + + #[cfg(feature = "with-chrono")] + use chrono::{NaiveDateTime, FixedOffset}; + + #[test] + fn timezone_comparison() { + let system = CFTimeZone::system(); + let default = CFTimeZone::default(); + assert_eq!(system, default); + } + + #[test] + #[cfg(feature = "with-chrono")] + fn timezone_chrono_conversion() { + let offset = FixedOffset::west(28800); + let tz = CFTimeZone::from_offset(offset); + let converted = tz.offset_at_date(NaiveDateTime::from_timestamp(0, 0)); + assert_eq!(offset, converted); + } +} diff --git a/third_party/cargo/vendor/core-foundation-0.9.1/src/url.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/url.rs new file mode 100644 index 0000000..064dd7b --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-0.9.1/src/url.rs @@ -0,0 +1,155 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A URL type for Core Foundation. + +pub use core_foundation_sys::url::*; + +use base::{TCFType, CFIndex}; +use string::{CFString}; + +use core_foundation_sys::base::{kCFAllocatorDefault, Boolean}; +use std::fmt; +use std::ptr; +use std::path::{Path, PathBuf}; + +use libc::{c_char, strlen, PATH_MAX}; + +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; +#[cfg(unix)] +use std::ffi::OsStr; + + +declare_TCFType!(CFURL, CFURLRef); +impl_TCFType!(CFURL, CFURLRef, CFURLGetTypeID); + +impl fmt::Debug for CFURL { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0)); + write!(f, "{}", string.to_string()) + } + } +} + +impl CFURL { + pub fn from_path>(path: P, isDirectory: bool) -> Option { + let path_bytes; + #[cfg(unix)] + { + path_bytes = path.as_ref().as_os_str().as_bytes() + } + #[cfg(not(unix))] + { + // XXX: Getting non-valid UTF8 paths into CoreFoundation on Windows is going to be unpleasant + // CFURLGetWideFileSystemRepresentation might help + path_bytes = match path.as_ref().to_str() { + Some(path) => path, + None => return None, + } + } + + unsafe { + let url_ref = CFURLCreateFromFileSystemRepresentation(ptr::null_mut(), path_bytes.as_ptr(), path_bytes.len() as CFIndex, isDirectory as u8); + if url_ref.is_null() { + return None; + } + Some(TCFType::wrap_under_create_rule(url_ref)) + } + } + + pub fn from_file_system_path(filePath: CFString, pathStyle: CFURLPathStyle, isDirectory: bool) -> CFURL { + unsafe { + let url_ref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath.as_concrete_TypeRef(), pathStyle, isDirectory as u8); + TCFType::wrap_under_create_rule(url_ref) + } + } + + #[cfg(unix)] + pub fn to_path(&self) -> Option { + // implementing this on Windows is more complicated because of the different OsStr representation + unsafe { + let mut buf = [0u8; PATH_MAX as usize]; + let result = CFURLGetFileSystemRepresentation(self.0, true as Boolean, buf.as_mut_ptr(), buf.len() as CFIndex); + if result == false as Boolean { + return None; + } + let len = strlen(buf.as_ptr() as *const c_char); + let path = OsStr::from_bytes(&buf[0..len]); + Some(PathBuf::from(path)) + } + } + + pub fn get_string(&self) -> CFString { + unsafe { + TCFType::wrap_under_get_rule(CFURLGetString(self.0)) + } + } + + pub fn get_file_system_path(&self, pathStyle: CFURLPathStyle) -> CFString { + unsafe { + TCFType::wrap_under_create_rule(CFURLCopyFileSystemPath(self.as_concrete_TypeRef(), pathStyle)) + } + } + + pub fn absolute(&self) -> CFURL { + unsafe { + TCFType::wrap_under_create_rule(CFURLCopyAbsoluteURL(self.as_concrete_TypeRef())) + } + } +} + +#[test] +fn file_url_from_path() { + let path = "/usr/local/foo/"; + let cfstr_path = CFString::from_static_string(path); + let cfurl = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + assert_eq!(cfurl.get_string().to_string(), "file:///usr/local/foo/"); +} + +#[cfg(unix)] +#[test] +fn non_utf8() { + use std::ffi::OsStr; + let path = Path::new(OsStr::from_bytes(b"/\xC0/blame")); + let cfurl = CFURL::from_path(path, false).unwrap(); + assert_eq!(cfurl.to_path().unwrap(), path); + let len = unsafe { CFURLGetBytes(cfurl.as_concrete_TypeRef(), ptr::null_mut(), 0) }; + assert_eq!(len, 17); +} + +#[test] +fn absolute_file_url() { + use core_foundation_sys::url::CFURLCreateWithFileSystemPathRelativeToBase; + use std::path::PathBuf; + + let path = "/usr/local/foo"; + let file = "bar"; + + let cfstr_path = CFString::from_static_string(path); + let cfstr_file = CFString::from_static_string(file); + let cfurl_base = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + let cfurl_relative: CFURL = unsafe { + let url_ref = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, + cfstr_file.as_concrete_TypeRef(), + kCFURLPOSIXPathStyle, + false as u8, + cfurl_base.as_concrete_TypeRef()); + TCFType::wrap_under_create_rule(url_ref) + }; + + let mut absolute_path = PathBuf::from(path); + absolute_path.push(file); + + assert_eq!(cfurl_relative.get_file_system_path(kCFURLPOSIXPathStyle).to_string(), file); + assert_eq!(cfurl_relative.absolute().get_file_system_path(kCFURLPOSIXPathStyle).to_string(), + absolute_path.to_str().unwrap()); +} diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/src/uuid.rs b/third_party/cargo/vendor/core-foundation-0.9.1/src/uuid.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/src/uuid.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/src/uuid.rs diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/tests/use_macro_outside_crate.rs b/third_party/cargo/vendor/core-foundation-0.9.1/tests/use_macro_outside_crate.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/tests/use_macro_outside_crate.rs rename to third_party/cargo/vendor/core-foundation-0.9.1/tests/use_macro_outside_crate.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/.cargo-checksum.json b/third_party/cargo/vendor/core-foundation-sys-0.6.2/.cargo-checksum.json deleted file mode 100644 index 72cdec6..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"dc9a55f461f23bf82bb9b3ee7d9b74807b7a905e31f05074bb05b5e3cb1ab267","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","build.rs":"9433ed3b20cc99e716dda4c6d8507c29bc04882544cbbea8d4e48ba80fd0fa12","src/array.rs":"40c305658e16b07d86353a5ad34e7b5fb98720f19cc2b5173360d6a61ce2642f","src/attributed_string.rs":"693b6c745c5aef1929595c94363d500b4b25ebcfed0b4b8dee0103b8fc0537f8","src/base.rs":"f0f8424099a4269e2359b063c3f055e115aec6df0f6aa71695ca91257dfd64e2","src/bundle.rs":"e8ad47f9f0280e1eef7e9aea2eb88020443953ac2cda234396321450ffc3d48a","src/data.rs":"4547e98f4e25a99606d8f33e82f8de3d9889612485d445d4467138b8ad29b7e9","src/date.rs":"c064ee4c3ebd1927532c34871e2e41179d6e3c3e400f6b409a18ad9e2337477f","src/dictionary.rs":"3327a6f90f1e0db5e3fde1973e2df4143ca896716a816d03f2b17c8e988c5159","src/error.rs":"6205ebeb7631daa8bcd560862b6daa10f640c8c117ce5f6f7184f268dcbcb42a","src/filedescriptor.rs":"49580654b657811fade7adaa256f5f895cb011c9baa4731e2f44a6ec7fdba235","src/lib.rs":"af7183760214be155e2cf562bf4265bd2d73da079e35d05e29ea0146e3c87654","src/messageport.rs":"e9227d5907cba8e29cdeea41bcb3ae5c7840220442953ab19aace31a84542f47","src/number.rs":"b1154203e74cb2258ba5520e20bcd4d524f1a957e09a19dd026b18d23baa3868","src/propertylist.rs":"7ec928438826c4ce40befedf3de0a37c8ecbc0fc17896dfa629d5864000b2cfe","src/runloop.rs":"67a6c2e4773f13de9452c9f8e4791b9889e03e56c07a7bdf64dbba99e9821f45","src/set.rs":"8aef5f4ba75a067e271ad6cb960569f1d22a0acee0eb6c79e31bb8b636619d9d","src/string.rs":"3ebfa11bba928d0ab1b07ecc0bd0f11367642eb818c8e21f08c16a4be8f9494f","src/timezone.rs":"42741f556af081be32987d2705488959c60aeb794e7c737b092f0dce5851ca89","src/url.rs":"4cd2950660ad234f7f833b3f5c092f7322465085452cca8ced623564400cdef9","src/uuid.rs":"82f75efa73d0842dff2e13d299c166c6593a77fcb69c4b7629a2df1c17ae507d"},"package":"e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/BUILD.bazel b/third_party/cargo/vendor/core-foundation-sys-0.6.2/BUILD.bazel deleted file mode 100644 index 01c6dea..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/BUILD.bazel +++ /dev/null @@ -1,55 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -# Unsupported target "build-script-build" with type "custom-build" omitted - -rust_library( - name = "core_foundation_sys", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.6.2", - # buildifier: leave-alone - deps = [ - ], -) diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/Cargo.toml b/third_party/cargo/vendor/core-foundation-sys-0.6.2/Cargo.toml deleted file mode 100644 index 565583b..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "core-foundation-sys" -version = "0.6.2" -authors = ["The Servo Project Developers"] -build = "build.rs" -description = "Bindings to Core Foundation for OS X" -homepage = "https://github.com/servo/core-foundation-rs" -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/core-foundation-rs" - -[dependencies] - -[features] -mac_os_10_7_support = [] -mac_os_10_8_features = [] diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/attributed_string.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/attributed_string.rs deleted file mode 100644 index ecdffe6..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/attributed_string.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; -use base::{CFAllocatorRef, CFTypeRef, CFIndex, CFRange, CFTypeID}; -use string::CFStringRef; -use dictionary::CFDictionaryRef; - -#[repr(C)] -pub struct __CFAttributedString(c_void); - -pub type CFAttributedStringRef = *const __CFAttributedString; -pub type CFMutableAttributedStringRef = *const __CFAttributedString; - -extern { - /* CFAttributedString */ - - pub fn CFAttributedStringCreate( - allocator: CFAllocatorRef, - str: CFStringRef, - attributes: CFDictionaryRef, - ) -> CFAttributedStringRef; - - pub fn CFAttributedStringGetLength(astr: CFAttributedStringRef) -> CFIndex; - - pub fn CFAttributedStringGetTypeID() -> CFTypeID; - - /* CFMutableAttributedString */ - - pub fn CFAttributedStringCreateMutableCopy( - allocator: CFAllocatorRef, max_length: CFIndex, astr: CFAttributedStringRef - ) -> CFMutableAttributedStringRef; - - pub fn CFAttributedStringCreateMutable( - allocator: CFAllocatorRef, - max_length: CFIndex, - ) -> CFMutableAttributedStringRef; - - pub fn CFAttributedStringReplaceString( - astr: CFMutableAttributedStringRef, range: CFRange, replacement: CFStringRef); - - pub fn CFAttributedStringSetAttribute( - astr: CFMutableAttributedStringRef, - range: CFRange, - attr_name: CFStringRef, - value: CFTypeRef, - ); - - pub fn CFMutableAttributedStringGetTypeID() -> CFTypeID; -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/base.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/base.rs deleted file mode 100644 index 8cbae38..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/base.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cmp::Ordering; -use std::os::raw::{c_uint, c_long, c_ulong, c_void, c_int}; -use string::CFStringRef; - -pub type Boolean = u8; -pub type CFIndex = c_long; -pub type mach_port_t = c_uint; -pub type CFAllocatorRef = *const c_void; -pub type CFNullRef = *const c_void; -pub type CFHashCode = c_ulong; -pub type CFTypeID = c_ulong; -pub type CFTypeRef = *const c_void; -pub type CFOptionFlags = u32; -pub type OSStatus = i32; -pub type SInt32 = c_int; - -#[repr(i64)] -#[derive(Clone, Copy)] -pub enum CFComparisonResult { - LessThan = -1, - EqualTo = 0, - GreaterThan = 1, -} - -impl Into for CFComparisonResult { - fn into(self) -> Ordering { - match self { - CFComparisonResult::LessThan => Ordering::Less, - CFComparisonResult::EqualTo => Ordering::Equal, - CFComparisonResult::GreaterThan => Ordering::Greater - } - } -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CFRange { - pub location: CFIndex, - pub length: CFIndex -} - -// for back-compat -impl CFRange { - pub fn init(location: CFIndex, length: CFIndex) -> CFRange { - CFRange { - location: location, - length: length, - } - } -} - -pub type CFAllocatorRetainCallBack = extern "C" fn(info: *mut c_void) -> *mut c_void; -pub type CFAllocatorReleaseCallBack = extern "C" fn(info: *mut c_void); -pub type CFAllocatorCopyDescriptionCallBack = extern "C" fn(info: *mut c_void) -> CFStringRef; -pub type CFAllocatorAllocateCallBack = extern "C" fn(allocSize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; -pub type CFAllocatorReallocateCallBack = extern "C" fn(ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; -pub type CFAllocatorDeallocateCallBack = extern "C" fn(ptr: *mut c_void, info: *mut c_void); -pub type CFAllocatorPreferredSizeCallBack = extern "C" fn(size: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> CFIndex; - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CFAllocatorContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: CFAllocatorRetainCallBack, - pub release: CFAllocatorReleaseCallBack, - pub copyDescription: CFAllocatorCopyDescriptionCallBack, - pub allocate: CFAllocatorAllocateCallBack, - pub reallocate: CFAllocatorReallocateCallBack, - pub deallocate: CFAllocatorDeallocateCallBack, - pub preferredSize: CFAllocatorPreferredSizeCallBack -} - -/// Trait for all types which are Core Foundation reference types. -pub trait TCFTypeRef { - fn as_void_ptr(&self) -> *const c_void; - - unsafe fn from_void_ptr(ptr: *const c_void) -> Self; -} - -impl TCFTypeRef for *const T { - fn as_void_ptr(&self) -> *const c_void { - (*self) as *const c_void - } - - unsafe fn from_void_ptr(ptr: *const c_void) -> Self { - ptr as *const T - } -} - -impl TCFTypeRef for *mut T { - fn as_void_ptr(&self) -> *const c_void { - (*self) as *const T as *const c_void - } - - unsafe fn from_void_ptr(ptr: *const c_void) -> Self { - ptr as *const T as *mut T - } -} - -extern { - /* - * CFBase.h - */ - - /* CFAllocator Reference */ - - pub static kCFAllocatorDefault: CFAllocatorRef; - pub static kCFAllocatorSystemDefault: CFAllocatorRef; - pub static kCFAllocatorMalloc: CFAllocatorRef; - pub static kCFAllocatorMallocZone: CFAllocatorRef; - pub static kCFAllocatorNull: CFAllocatorRef; - pub static kCFAllocatorUseContext: CFAllocatorRef; - - pub fn CFAllocatorCreate(allocator: CFAllocatorRef, context: *mut CFAllocatorContext) -> CFAllocatorRef; - pub fn CFAllocatorAllocate(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> *mut c_void; - pub fn CFAllocatorDeallocate(allocator: CFAllocatorRef, ptr: *mut c_void); - pub fn CFAllocatorGetPreferredSizeForSize(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> CFIndex; - pub fn CFAllocatorReallocate(allocator: CFAllocatorRef, ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags) -> *mut c_void; - pub fn CFAllocatorGetDefault() -> CFAllocatorRef; - pub fn CFAllocatorSetDefault(allocator: CFAllocatorRef); - pub fn CFAllocatorGetContext(allocator: CFAllocatorRef, context: *mut CFAllocatorContext); - pub fn CFAllocatorGetTypeID() -> CFTypeID; - - /* CFNull Reference */ - - pub static kCFNull: CFNullRef; - - /* CFType Reference */ - - //fn CFCopyTypeIDDescription - //fn CFGetAllocator - pub fn CFCopyDescription(cf: CFTypeRef) -> CFStringRef; - pub fn CFEqual(cf1: CFTypeRef, cf2: CFTypeRef) -> Boolean; - pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex; - pub fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID; - pub fn CFHash(cf: CFTypeRef) -> CFHashCode; - //fn CFMakeCollectable - pub fn CFRelease(cf: CFTypeRef); - pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef; - pub fn CFShow(obj: CFTypeRef); - - /* Base Utilities Reference */ - // N.B. Some things missing here. -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/bundle.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/bundle.rs deleted file mode 100644 index 687b00e..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/bundle.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use base::{CFTypeID, CFAllocatorRef}; -use url::CFURLRef; -use dictionary::CFDictionaryRef; -use string::CFStringRef; - -#[repr(C)] -pub struct __CFBundle(c_void); - -pub type CFBundleRef = *mut __CFBundle; - -extern { - /* - * CFBundle.h - */ - pub fn CFBundleCreate(allocator: CFAllocatorRef, bundleURL: CFURLRef) -> CFBundleRef; - - pub fn CFBundleGetBundleWithIdentifier(bundleID: CFStringRef) -> CFBundleRef; - pub fn CFBundleGetFunctionPointerForName(bundle: CFBundleRef, function_name: CFStringRef) -> *const c_void; - pub fn CFBundleGetMainBundle() -> CFBundleRef; - pub fn CFBundleGetInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; - - pub fn CFBundleGetTypeID() -> CFTypeID; - pub fn CFBundleCopyExecutableURL(bundle: CFBundleRef) -> CFURLRef; - pub fn CFBundleCopyPrivateFrameworksURL(bundle: CFBundleRef) -> CFURLRef; -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/data.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/data.rs deleted file mode 100644 index 51b3a4c..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/data.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use base::{CFAllocatorRef, CFTypeID, CFIndex}; - -#[repr(C)] -pub struct __CFData(c_void); - -pub type CFDataRef = *const __CFData; - -extern { - /* - * CFData.h - */ - - pub fn CFDataCreate(allocator: CFAllocatorRef, - bytes: *const u8, length: CFIndex) -> CFDataRef; - //fn CFDataFind - pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8; - pub fn CFDataGetLength(theData: CFDataRef) -> CFIndex; - - pub fn CFDataGetTypeID() -> CFTypeID; -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/lib.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/lib.rs deleted file mode 100644 index e03cddb..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals, improper_ctypes)] - -#![cfg_attr(all(feature="mac_os_10_7_support", feature="mac_os_10_8_features"), feature(linkage))] // back-compat requires weak linkage - -pub mod array; -pub mod attributed_string; -pub mod base; -pub mod bundle; -pub mod data; -pub mod date; -pub mod dictionary; -pub mod error; -pub mod filedescriptor; -pub mod messageport; -pub mod number; -pub mod propertylist; -pub mod runloop; -pub mod set; -pub mod string; -pub mod timezone; -pub mod url; -pub mod uuid; diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/number.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/number.rs deleted file mode 100644 index 931b95d..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/number.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use base::{CFAllocatorRef, CFTypeID, CFComparisonResult}; - -#[repr(C)] -pub struct __CFBoolean(c_void); - -pub type CFBooleanRef = *const __CFBoolean; - -pub type CFNumberType = u32; - -// members of enum CFNumberType -// static kCFNumberSInt8Type: CFNumberType = 1; -// static kCFNumberSInt16Type: CFNumberType = 2; -pub static kCFNumberSInt32Type: CFNumberType = 3; -pub static kCFNumberSInt64Type: CFNumberType = 4; -pub static kCFNumberFloat32Type: CFNumberType = 5; -pub static kCFNumberFloat64Type: CFNumberType = 6; -// static kCFNumberCharType: CFNumberType = 7; -// static kCFNumberShortType: CFNumberType = 8; -// static kCFNumberIntType: CFNumberType = 9; -// static kCFNumberLongType: CFNumberType = 10; -// static kCFNumberLongLongType: CFNumberType = 11; -// static kCFNumberFloatType: CFNumberType = 12; -// static kCFNumberDoubleType: CFNumberType = 13; -// static kCFNumberCFIndexType: CFNumberType = 14; -// static kCFNumberNSIntegerType: CFNumberType = 15; -// static kCFNumberCGFloatType: CFNumberType = 16; -// static kCFNumberMaxType: CFNumberType = 16; - -// This is an enum due to zero-sized types warnings. -// For more details see https://github.com/rust-lang/rust/issues/27303 -pub enum __CFNumber {} - -pub type CFNumberRef = *const __CFNumber; - -extern { - /* - * CFNumber.h - */ - pub static kCFBooleanTrue: CFBooleanRef; - pub static kCFBooleanFalse: CFBooleanRef; - - pub fn CFBooleanGetTypeID() -> CFTypeID; - pub fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *const c_void) - -> CFNumberRef; - //fn CFNumberGetByteSize - pub fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *mut c_void) -> bool; - pub fn CFNumberCompare(date: CFNumberRef, other: CFNumberRef, context: *mut c_void) -> CFComparisonResult; - pub fn CFNumberGetTypeID() -> CFTypeID; -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/runloop.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/runloop.rs deleted file mode 100644 index 5de7b87..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/runloop.rs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use array::CFArrayRef; -use base::{Boolean, CFIndex, CFTypeID, CFAllocatorRef, CFOptionFlags, CFHashCode, mach_port_t}; -use date::{CFAbsoluteTime, CFTimeInterval}; -use string::CFStringRef; - -#[repr(C)] -pub struct __CFRunLoop(c_void); - -pub type CFRunLoopRef = *mut __CFRunLoop; - -#[repr(C)] -pub struct __CFRunLoopSource(c_void); - -pub type CFRunLoopSourceRef = *mut __CFRunLoopSource; - -#[repr(C)] -pub struct __CFRunLoopObserver(c_void); - -pub type CFRunLoopObserverRef = *mut __CFRunLoopObserver; - -// Reasons for CFRunLoopRunInMode() to Return -pub const kCFRunLoopRunFinished: i32 = 1; -pub const kCFRunLoopRunStopped: i32 = 2; -pub const kCFRunLoopRunTimedOut: i32 = 3; -pub const kCFRunLoopRunHandledSource: i32 = 4; - -// Run Loop Observer Activities -//typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { -pub type CFRunLoopActivity = CFOptionFlags; -pub const kCFRunLoopEntry: CFOptionFlags = 1 << 0; -pub const kCFRunLoopBeforeTimers: CFOptionFlags = 1 << 1; -pub const kCFRunLoopBeforeSources: CFOptionFlags = 1 << 2; -pub const kCFRunLoopBeforeWaiting: CFOptionFlags = 1 << 5; -pub const kCFRunLoopAfterWaiting: CFOptionFlags = 1 << 6; -pub const kCFRunLoopExit: CFOptionFlags = 1 << 7; -pub const kCFRunLoopAllActivities: CFOptionFlags = 0x0FFFFFFF; - -#[repr(C)] -pub struct CFRunLoopSourceContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, - pub equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean, - pub hash: extern "C" fn (info: *const c_void) -> CFHashCode, - pub schedule: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef), - pub cancel: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef), - pub perform: extern "C" fn (info: *const c_void), -} - -#[repr(C)] -pub struct CFRunLoopSourceContext1 { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, - pub equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean, - pub hash: extern "C" fn (info: *const c_void) -> CFHashCode, - // note that the following two fields are platform dependent in the C header, the ones here are for OS X - pub getPort: extern "C" fn (info: *mut c_void) -> mach_port_t, - pub perform: extern "C" fn (msg: *mut c_void, size: CFIndex, allocator: CFAllocatorRef, info: *mut c_void) -> *mut c_void, -} - -#[repr(C)] -pub struct CFRunLoopObserverContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, -} - -pub type CFRunLoopObserverCallBack = extern "C" fn (observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); - -#[repr(C)] -pub struct CFRunLoopTimerContext { - pub version: CFIndex, - pub info: *mut c_void, - pub retain: extern "C" fn (info: *const c_void) -> *const c_void, - pub release: extern "C" fn (info: *const c_void), - pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, -} - -pub type CFRunLoopTimerCallBack = extern "C" fn (timer: CFRunLoopTimerRef, info: *mut c_void); - -#[repr(C)] -pub struct __CFRunLoopTimer; - -pub type CFRunLoopTimerRef = *mut __CFRunLoopTimer; - -extern { - /* - * CFRunLoop.h - */ - pub static kCFRunLoopDefaultMode: CFStringRef; - pub static kCFRunLoopCommonModes: CFStringRef; - pub fn CFRunLoopGetTypeID() -> CFTypeID; - pub fn CFRunLoopGetCurrent() -> CFRunLoopRef; - pub fn CFRunLoopGetMain() -> CFRunLoopRef; - pub fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef; - pub fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef; - pub fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef); - pub fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime; - pub fn CFRunLoopRun(); - pub fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32; - pub fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean; - pub fn CFRunLoopWakeUp(rl: CFRunLoopRef); - pub fn CFRunLoopStop(rl: CFRunLoopRef); - // fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void)); - pub fn CFRunLoopContainsSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); - pub fn CFRunLoopRemoveSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); - pub fn CFRunLoopContainsObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); - pub fn CFRunLoopRemoveObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); - pub fn CFRunLoopContainsTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef) -> Boolean; - pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); - pub fn CFRunLoopRemoveTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); - - pub fn CFRunLoopSourceGetTypeID() -> CFTypeID; - pub fn CFRunLoopSourceCreate(allocator: CFAllocatorRef, order: CFIndex, context: *mut CFRunLoopSourceContext) -> CFRunLoopSourceRef; - pub fn CFRunLoopSourceGetOrder(source: CFRunLoopSourceRef) -> CFIndex; - pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); - pub fn CFRunLoopSourceIsValid(source: CFRunLoopSourceRef) -> Boolean; - pub fn CFRunLoopSourceGetContext(source: CFRunLoopSourceRef, context: *mut CFRunLoopSourceContext); - pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); - - pub fn CFRunLoopObserverGetTypeID() -> CFTypeID; - pub fn CFRunLoopObserverCreate(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, callout: CFRunLoopObserverCallBack, context: *mut CFRunLoopObserverContext) -> CFRunLoopObserverRef; - // fn CFRunLoopObserverCreateWithHandler(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, block: void (^) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) -> CFRunLoopObserverRef; - pub fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags; - pub fn CFRunLoopObserverDoesRepeat(observer: CFRunLoopObserverRef) -> Boolean; - pub fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserverRef) -> CFIndex; - pub fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserverRef); - pub fn CFRunLoopObserverIsValid(observer: CFRunLoopObserverRef) -> Boolean; - pub fn CFRunLoopObserverGetContext(observer: CFRunLoopObserverRef, context: *mut CFRunLoopObserverContext); - - pub fn CFRunLoopTimerGetTypeID() -> CFTypeID; - pub fn CFRunLoopTimerCreate(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimerRef; - // fn CFRunLoopTimerCreateWithHandler(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, block: void (^) (CFRunLoopTimerRef timer)) -> CFRunLoopTimerRef; - pub fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime; - pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); - pub fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval; - pub fn CFRunLoopTimerDoesRepeat(timer: CFRunLoopTimerRef) -> Boolean; - pub fn CFRunLoopTimerGetOrder(timer: CFRunLoopTimerRef) -> CFIndex; - pub fn CFRunLoopTimerInvalidate(timer: CFRunLoopTimerRef); - pub fn CFRunLoopTimerIsValid(timer: CFRunLoopTimerRef) -> Boolean; - pub fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext); - pub fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval; - pub fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval); -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/set.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/set.rs deleted file mode 100644 index ec4a4bd..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/set.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use base::{CFAllocatorRef, CFIndex, CFTypeID}; - -pub type CFSetApplierFunction = extern "C" fn (value: *const c_void, - context: *const c_void); -pub type CFSetRetainCallBack = *const u8; -pub type CFSetReleaseCallBack = *const u8; -pub type CFSetCopyDescriptionCallBack = *const u8; -pub type CFSetEqualCallBack = *const u8; -pub type CFSetHashCallBack = *const u8; - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CFSetCallBacks { - pub version: CFIndex, - pub retain: CFSetRetainCallBack, - pub release: CFSetReleaseCallBack, - pub copyDescription: CFSetCopyDescriptionCallBack, - pub equal: CFSetEqualCallBack, - pub hash: CFSetHashCallBack, -} - -#[repr(C)] -pub struct __CFSet(c_void); - -pub type CFSetRef = *const __CFSet; - -extern { - /* - * CFSet.h - */ - - pub static kCFTypeSetCallBacks: CFSetCallBacks; - - /* Creating Sets */ - pub fn CFSetCreate(allocator: CFAllocatorRef, values: *const *const c_void, numValues: CFIndex, - callBacks: *const CFSetCallBacks) -> CFSetRef; - - /* Applying a Function to Set Members */ - pub fn CFSetApplyFunction(theSet: CFSetRef, - applier: CFSetApplierFunction, - context: *const c_void); - - pub fn CFSetGetCount(theSet: CFSetRef) -> CFIndex; - - pub fn CFSetGetTypeID() -> CFTypeID; -} - diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/string.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/string.rs deleted file mode 100644 index a990d96..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/string.rs +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::{c_char, c_ushort, c_void}; - -use base::{Boolean, CFOptionFlags, CFIndex, CFAllocatorRef, CFRange, CFTypeID}; - -pub type UniChar = c_ushort; - -// CFString.h - -pub type CFStringCompareFlags = CFOptionFlags; -//static kCFCompareCaseInsensitive: CFStringCompareFlags = 1; -//static kCFCompareBackwards: CFStringCompareFlags = 4; -//static kCFCompareAnchored: CFStringCompareFlags = 8; -//static kCFCompareNonliteral: CFStringCompareFlags = 16; -//static kCFCompareLocalized: CFStringCompareFlags = 32; -//static kCFCompareNumerically: CFStringCompareFlags = 64; -//static kCFCompareDiacriticInsensitive: CFStringCompareFlags = 128; -//static kCFCompareWidthInsensitive: CFStringCompareFlags = 256; -//static kCFCompareForcedOrdering: CFStringCompareFlags = 512; - -pub type CFStringEncoding = u32; - -// OS X built-in encodings. - -//static kCFStringEncodingMacRoman: CFStringEncoding = 0; -//static kCFStringEncodingWindowsLatin1: CFStringEncoding = 0x0500; -//static kCFStringEncodingISOLatin1: CFStringEncoding = 0x0201; -//static kCFStringEncodingNextStepLatin: CFStringEncoding = 0x0B01; -//static kCFStringEncodingASCII: CFStringEncoding = 0x0600; -//static kCFStringEncodingUnicode: CFStringEncoding = 0x0100; -pub static kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; -//static kCFStringEncodingNonLossyASCII: CFStringEncoding = 0x0BFF; - -//static kCFStringEncodingUTF16: CFStringEncoding = 0x0100; -//static kCFStringEncodingUTF16BE: CFStringEncoding = 0x10000100; -//static kCFStringEncodingUTF16LE: CFStringEncoding = 0x14000100; -//static kCFStringEncodingUTF32: CFStringEncoding = 0x0c000100; -//static kCFStringEncodingUTF32BE: CFStringEncoding = 0x18000100; -//static kCFStringEncodingUTF32LE: CFStringEncoding = 0x1c000100; - - -// CFStringEncodingExt.h - -pub type CFStringEncodings = CFIndex; - -// External encodings, except those defined above. -// Defined above: kCFStringEncodingMacRoman = 0 -//static kCFStringEncodingMacJapanese: CFStringEncoding = 1; -//static kCFStringEncodingMacChineseTrad: CFStringEncoding = 2; -//static kCFStringEncodingMacKorean: CFStringEncoding = 3; -//static kCFStringEncodingMacArabic: CFStringEncoding = 4; -//static kCFStringEncodingMacHebrew: CFStringEncoding = 5; -//static kCFStringEncodingMacGreek: CFStringEncoding = 6; -//static kCFStringEncodingMacCyrillic: CFStringEncoding = 7; -//static kCFStringEncodingMacDevanagari: CFStringEncoding = 9; -//static kCFStringEncodingMacGurmukhi: CFStringEncoding = 10; -//static kCFStringEncodingMacGujarati: CFStringEncoding = 11; -//static kCFStringEncodingMacOriya: CFStringEncoding = 12; -//static kCFStringEncodingMacBengali: CFStringEncoding = 13; -//static kCFStringEncodingMacTamil: CFStringEncoding = 14; -//static kCFStringEncodingMacTelugu: CFStringEncoding = 15; -//static kCFStringEncodingMacKannada: CFStringEncoding = 16; -//static kCFStringEncodingMacMalayalam: CFStringEncoding = 17; -//static kCFStringEncodingMacSinhalese: CFStringEncoding = 18; -//static kCFStringEncodingMacBurmese: CFStringEncoding = 19; -//static kCFStringEncodingMacKhmer: CFStringEncoding = 20; -//static kCFStringEncodingMacThai: CFStringEncoding = 21; -//static kCFStringEncodingMacLaotian: CFStringEncoding = 22; -//static kCFStringEncodingMacGeorgian: CFStringEncoding = 23; -//static kCFStringEncodingMacArmenian: CFStringEncoding = 24; -//static kCFStringEncodingMacChineseSimp: CFStringEncoding = 25; -//static kCFStringEncodingMacTibetan: CFStringEncoding = 26; -//static kCFStringEncodingMacMongolian: CFStringEncoding = 27; -//static kCFStringEncodingMacEthiopic: CFStringEncoding = 28; -//static kCFStringEncodingMacCentralEurRoman: CFStringEncoding = 29; -//static kCFStringEncodingMacVietnamese: CFStringEncoding = 30; -//static kCFStringEncodingMacExtArabic: CFStringEncoding = 31; -//static kCFStringEncodingMacSymbol: CFStringEncoding = 33; -//static kCFStringEncodingMacDingbats: CFStringEncoding = 34; -//static kCFStringEncodingMacTurkish: CFStringEncoding = 35; -//static kCFStringEncodingMacCroatian: CFStringEncoding = 36; -//static kCFStringEncodingMacIcelandic: CFStringEncoding = 37; -//static kCFStringEncodingMacRomanian: CFStringEncoding = 38; -//static kCFStringEncodingMacCeltic: CFStringEncoding = 39; -//static kCFStringEncodingMacGaelic: CFStringEncoding = 40; -//static kCFStringEncodingMacFarsi: CFStringEncoding = 0x8C; -//static kCFStringEncodingMacUkrainian: CFStringEncoding = 0x98; -//static kCFStringEncodingMacInuit: CFStringEncoding = 0xEC; -//static kCFStringEncodingMacVT100: CFStringEncoding = 0xFC; -//static kCFStringEncodingMacHFS: CFStringEncoding = 0xFF; -// Defined above: kCFStringEncodingISOLatin1 = 0x0201 -//static kCFStringEncodingISOLatin2: CFStringEncoding = 0x0202; -//static kCFStringEncodingISOLatin3: CFStringEncoding = 0x0203; -//static kCFStringEncodingISOLatin4: CFStringEncoding = 0x0204; -//static kCFStringEncodingISOLatinCyrillic: CFStringEncoding = 0x0205; -//static kCFStringEncodingISOLatinArabic: CFStringEncoding = 0x0206; -//static kCFStringEncodingISOLatinGreek: CFStringEncoding = 0x0207; -//static kCFStringEncodingISOLatinHebrew: CFStringEncoding = 0x0208; -//static kCFStringEncodingISOLatin5: CFStringEncoding = 0x0209; -//static kCFStringEncodingISOLatin6: CFStringEncoding = 0x020A; -//static kCFStringEncodingISOLatinThai: CFStringEncoding = 0x020B; -//static kCFStringEncodingISOLatin7: CFStringEncoding = 0x020D; -//static kCFStringEncodingISOLatin8: CFStringEncoding = 0x020E; -//static kCFStringEncodingISOLatin9: CFStringEncoding = 0x020F; -//static kCFStringEncodingISOLatin10: CFStringEncoding = 0x0210; -//static kCFStringEncodingDOSLatinUS: CFStringEncoding = 0x0400; -//static kCFStringEncodingDOSGreek: CFStringEncoding = 0x0405; -//static kCFStringEncodingDOSBalticRim: CFStringEncoding = 0x0406; -//static kCFStringEncodingDOSLatin1: CFStringEncoding = 0x0410; -//static kCFStringEncodingDOSGreek1: CFStringEncoding = 0x0411; -//static kCFStringEncodingDOSLatin2: CFStringEncoding = 0x0412; -//static kCFStringEncodingDOSCyrillic: CFStringEncoding = 0x0413; -//static kCFStringEncodingDOSTurkish: CFStringEncoding = 0x0414; -//static kCFStringEncodingDOSPortuguese: CFStringEncoding = 0x0415; -//static kCFStringEncodingDOSIcelandic: CFStringEncoding = 0x0416; -//static kCFStringEncodingDOSHebrew: CFStringEncoding = 0x0417; -//static kCFStringEncodingDOSCanadianFrench: CFStringEncoding = 0x0418; -//static kCFStringEncodingDOSArabic: CFStringEncoding = 0x0419; -//static kCFStringEncodingDOSNordic: CFStringEncoding = 0x041A; -//static kCFStringEncodingDOSRussian: CFStringEncoding = 0x041B; -//static kCFStringEncodingDOSGreek2: CFStringEncoding = 0x041C; -//static kCFStringEncodingDOSThai: CFStringEncoding = 0x041D; -//static kCFStringEncodingDOSJapanese: CFStringEncoding = 0x0420; -//static kCFStringEncodingDOSChineseSimplif: CFStringEncoding = 0x0421; -//static kCFStringEncodingDOSKorean: CFStringEncoding = 0x0422; -//static kCFStringEncodingDOSChineseTrad: CFStringEncoding = 0x0423; -// Defined above: kCFStringEncodingWindowsLatin1 = 0x0500 -//static kCFStringEncodingWindowsLatin2: CFStringEncoding = 0x0501; -//static kCFStringEncodingWindowsCyrillic: CFStringEncoding = 0x0502; -//static kCFStringEncodingWindowsGreek: CFStringEncoding = 0x0503; -//static kCFStringEncodingWindowsLatin5: CFStringEncoding = 0x0504; -//static kCFStringEncodingWindowsHebrew: CFStringEncoding = 0x0505; -//static kCFStringEncodingWindowsArabic: CFStringEncoding = 0x0506; -//static kCFStringEncodingWindowsBalticRim: CFStringEncoding = 0x0507; -//static kCFStringEncodingWindowsVietnamese: CFStringEncoding = 0x0508; -//static kCFStringEncodingWindowsKoreanJohab: CFStringEncoding = 0x0510; -// Defined above: kCFStringEncodingASCII = 0x0600 -//static kCFStringEncodingANSEL: CFStringEncoding = 0x0601; -//static kCFStringEncodingJIS_X0201_76: CFStringEncoding = 0x0620; -//static kCFStringEncodingJIS_X0208_83: CFStringEncoding = 0x0621; -//static kCFStringEncodingJIS_X0208_90: CFStringEncoding = 0x0622; -//static kCFStringEncodingJIS_X0212_90: CFStringEncoding = 0x0623; -//static kCFStringEncodingJIS_C6226_78: CFStringEncoding = 0x0624; -//static kCFStringEncodingShiftJIS_X0213: CFStringEncoding = 0x0628; -//static kCFStringEncodingShiftJIS_X0213_MenKuTen: CFStringEncoding = 0x0629; -//static kCFStringEncodingGB_2312_80: CFStringEncoding = 0x0630; -//static kCFStringEncodingGBK_95: CFStringEncoding = 0x0631; -//static kCFStringEncodingGB_18030_2000: CFStringEncoding = 0x0632; -//static kCFStringEncodingKSC_5601_87: CFStringEncoding = 0x0640; -//static kCFStringEncodingKSC_5601_92_Johab: CFStringEncoding = 0x0641; -//static kCFStringEncodingCNS_11643_92_P1: CFStringEncoding = 0x0651; -//static kCFStringEncodingCNS_11643_92_P2: CFStringEncoding = 0x0652; -//static kCFStringEncodingCNS_11643_92_P3: CFStringEncoding = 0x0653; -//static kCFStringEncodingISO_2022_JP: CFStringEncoding = 0x0820; -//static kCFStringEncodingISO_2022_JP_2: CFStringEncoding = 0x0821; -//static kCFStringEncodingISO_2022_JP_1: CFStringEncoding = 0x0822; -//static kCFStringEncodingISO_2022_JP_3: CFStringEncoding = 0x0823; -//static kCFStringEncodingISO_2022_CN: CFStringEncoding = 0x0830; -//static kCFStringEncodingISO_2022_CN_EXT: CFStringEncoding = 0x0831; -//static kCFStringEncodingISO_2022_KR: CFStringEncoding = 0x0840; -//static kCFStringEncodingEUC_JP: CFStringEncoding = 0x0920; -//static kCFStringEncodingEUC_CN: CFStringEncoding = 0x0930; -//static kCFStringEncodingEUC_TW: CFStringEncoding = 0x0931; -//static kCFStringEncodingEUC_KR: CFStringEncoding = 0x0940; -//static kCFStringEncodingShiftJIS: CFStringEncoding = 0x0A01; -//static kCFStringEncodingKOI8_R: CFStringEncoding = 0x0A02; -//static kCFStringEncodingBig5: CFStringEncoding = 0x0A03; -//static kCFStringEncodingMacRomanLatin1: CFStringEncoding = 0x0A04; -//static kCFStringEncodingHZ_GB_2312: CFStringEncoding = 0x0A05; -//static kCFStringEncodingBig5_HKSCS_1999: CFStringEncoding = 0x0A06; -//static kCFStringEncodingVISCII: CFStringEncoding = 0x0A07; -//static kCFStringEncodingKOI8_U: CFStringEncoding = 0x0A08; -//static kCFStringEncodingBig5_E: CFStringEncoding = 0x0A09; -// Defined above: kCFStringEncodingNextStepLatin = 0x0B01 -//static kCFStringEncodingNextStepJapanese: CFStringEncoding = 0x0B02; -//static kCFStringEncodingEBCDIC_US: CFStringEncoding = 0x0C01; -//static kCFStringEncodingEBCDIC_CP037: CFStringEncoding = 0x0C02; -//static kCFStringEncodingUTF7: CFStringEncoding = 0x04000100; -//static kCFStringEncodingUTF7_IMAP: CFStringEncoding = 0x0A10; -//static kCFStringEncodingShiftJIS_X0213_00: CFStringEncoding = 0x0628; /* Deprecated */ - -#[repr(C)] -pub struct __CFString(c_void); - -pub type CFStringRef = *const __CFString; - -extern { - /* - * CFString.h - */ - - // N.B. organized according to "Functions by task" in docs - - /* Creating a CFString */ - //fn CFSTR - //fn CFStringCreateArrayBySeparatingStrings - //fn CFStringCreateByCombiningStrings - //fn CFStringCreateCopy - //fn CFStringCreateFromExternalRepresentation - pub fn CFStringCreateWithBytes(alloc: CFAllocatorRef, - bytes: *const u8, - numBytes: CFIndex, - encoding: CFStringEncoding, - isExternalRepresentation: Boolean) - -> CFStringRef; - pub fn CFStringCreateWithBytesNoCopy(alloc: CFAllocatorRef, - bytes: *const u8, - numBytes: CFIndex, - encoding: CFStringEncoding, - isExternalRepresentation: Boolean, - contentsDeallocator: CFAllocatorRef) - -> CFStringRef; - //fn CFStringCreateWithCharacters - //fn CFStringCreateWithCharactersNoCopy - pub fn CFStringCreateWithCString(alloc: CFAllocatorRef, - cStr: *const c_char, - encoding: CFStringEncoding) - -> CFStringRef; - //fn CFStringCreateWithCStringNoCopy - //fn CFStringCreateWithFormat - //fn CFStringCreateWithFormatAndArguments - //fn CFStringCreateWithPascalString - //fn CFStringCreateWithPascalStringNoCopy - //fn CFStringCreateWithSubstring - - /* Searching Strings */ - //fn CFStringCreateArrayWithFindResults - //fn CFStringFind - //fn CFStringFindCharacterFromSet - //fn CFStringFindWithOptions - //fn CFStringFindWithOptionsAndLocale - //fn CFStringGetLineBounds - - /* Comparing Strings */ - //fn CFStringCompare - //fn CFStringCompareWithOptions - //fn CFStringCompareWithOptionsAndLocale - //fn CFStringHasPrefix - //fn CFStringHasSuffix - - /* Accessing Characters */ - //fn CFStringCreateExternalRepresentation - pub fn CFStringGetBytes(theString: CFStringRef, - range: CFRange, - encoding: CFStringEncoding, - lossByte: u8, - isExternalRepresentation: Boolean, - buffer: *mut u8, - maxBufLen: CFIndex, - usedBufLen: *mut CFIndex) - -> CFIndex; - //fn CFStringGetCharacterAtIndex - //fn CFStringGetCharacters - //fn CFStringGetCharactersPtr - //fn CFStringGetCharacterFromInlineBuffer - pub fn CFStringGetCString(theString: CFStringRef, - buffer: *mut c_char, - bufferSize: CFIndex, - encoding: CFStringEncoding) - -> Boolean; - pub fn CFStringGetCStringPtr(theString: CFStringRef, - encoding: CFStringEncoding) - -> *const c_char; - pub fn CFStringGetLength(theString: CFStringRef) -> CFIndex; - //fn CFStringGetPascalString - //fn CFStringGetPascalStringPtr - //fn CFStringGetRangeOfComposedCharactersAtIndex - //fn CFStringInitInlineBuffer - - /* Working With Hyphenation */ - //fn CFStringGetHyphenationLocationBeforeIndex - //fn CFStringIsHyphenationAvailableForLocale - - /* Working With Encodings */ - //fn CFStringConvertEncodingToIANACharSetName - //fn CFStringConvertEncodingToNSStringEncoding - //fn CFStringConvertEncodingToWindowsCodepage - //fn CFStringConvertIANACharSetNameToEncoding - //fn CFStringConvertNSStringEncodingToEncoding - //fn CFStringConvertWindowsCodepageToEncoding - //fn CFStringGetFastestEncoding - //fn CFStringGetListOfAvailableEncodings - //fn CFStringGetMaximumSizeForEncoding - //fn CFStringGetMostCompatibleMacStringEncoding - //fn CFStringGetNameOfEncoding - //fn CFStringGetSmallestEncoding - //fn CFStringGetSystemEncoding - //fn CFStringIsEncodingAvailable - - /* Getting Numeric Values */ - //fn CFStringGetDoubleValue - //fn CFStringGetIntValue - - /* Getting String Properties */ - //fn CFShowStr - pub fn CFStringGetTypeID() -> CFTypeID; - - /* String File System Representations */ - //fn CFStringCreateWithFileSystemRepresentation - //fn CFStringGetFileSystemRepresentation - //fn CFStringGetMaximumSizeOfFileSystemRepresentation - - /* Getting Paragraph Bounds */ - //fn CFStringGetParagraphBounds - - /* Managing Surrogates */ - //fn CFStringGetLongCharacterForSurrogatePair - //fn CFStringGetSurrogatePairForLongCharacter - //fn CFStringIsSurrogateHighCharacter - //fn CFStringIsSurrogateLowCharacter -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/timezone.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/timezone.rs deleted file mode 100644 index 376cfdc..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/timezone.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use base::{CFAllocatorRef, CFTypeID}; -use date::{CFTimeInterval, CFAbsoluteTime}; - -#[repr(C)] -pub struct __CFTimeZone(c_void); - -pub type CFTimeZoneRef = *const __CFTimeZone; - -extern { - pub fn CFTimeZoneCopySystem() -> CFTimeZoneRef; - pub fn CFTimeZoneCopyDefault() -> CFTimeZoneRef; - pub fn CFTimeZoneCreateWithTimeIntervalFromGMT(allocator: CFAllocatorRef, interval: CFTimeInterval) -> CFTimeZoneRef; - pub fn CFTimeZoneGetSecondsFromGMT(tz: CFTimeZoneRef, time: CFAbsoluteTime) -> CFTimeInterval; - - pub fn CFTimeZoneGetTypeID() -> CFTypeID; -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/url.rs b/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/url.rs deleted file mode 100644 index 9c4bc3e..0000000 --- a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/url.rs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::os::raw::c_void; - -use base::{CFOptionFlags, CFIndex, CFAllocatorRef, Boolean, CFTypeID, CFTypeRef, SInt32}; -use string::{CFStringRef, CFStringEncoding}; -use error::CFErrorRef; - -#[repr(C)] -pub struct __CFURL(c_void); - -pub type CFURLRef = *const __CFURL; - -pub type CFURLBookmarkCreationOptions = CFOptionFlags; - -pub type CFURLPathStyle = CFIndex; - -/* typedef CF_ENUM(CFIndex, CFURLPathStyle) */ -pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; -pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; -pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2; - -// static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions = -// (1 << 8) as u32; -// static kCFURLBookmarkCreationMinimalBookmarkMask: CFURLBookmarkCreationOptions = -// (1 << 9) as u32; -// static kCFURLBookmarkCreationSuitableForBookmarkFile: CFURLBookmarkCreationOptions = -// (1 << 10) as u32; -// static kCFURLBookmarkCreationWithSecurityScope: CFURLBookmarkCreationOptions = -// (1 << 11) as u32; -// static kCFURLBookmarkCreationSecurityScopeAllowOnlyReadAccess: CFURLBookmarkCreationOptions = -// (1 << 12) as u32; - -// TODO: there are a lot of missing keys and constants. Add if you are bored or need them. - -extern { - /* - * CFURL.h - */ - - /* Common File System Resource Keys */ - pub static kCFURLAttributeModificationDateKey: CFStringRef; - pub static kCFURLContentAccessDateKey: CFStringRef; - pub static kCFURLContentModificationDateKey: CFStringRef; - pub static kCFURLCreationDateKey: CFStringRef; - pub static kCFURLFileResourceIdentifierKey: CFStringRef; - pub static kCFURLFileSecurityKey: CFStringRef; - pub static kCFURLHasHiddenExtensionKey: CFStringRef; - pub static kCFURLIsDirectoryKey: CFStringRef; - pub static kCFURLIsExecutableKey: CFStringRef; - pub static kCFURLIsHiddenKey: CFStringRef; - pub static kCFURLIsPackageKey: CFStringRef; - pub static kCFURLIsReadableKey: CFStringRef; - pub static kCFURLIsRegularFileKey: CFStringRef; - pub static kCFURLIsSymbolicLinkKey: CFStringRef; - pub static kCFURLIsSystemImmutableKey: CFStringRef; - pub static kCFURLIsUserImmutableKey: CFStringRef; - pub static kCFURLIsVolumeKey: CFStringRef; - pub static kCFURLIsWritableKey: CFStringRef; - pub static kCFURLLabelNumberKey: CFStringRef; - pub static kCFURLLinkCountKey: CFStringRef; - pub static kCFURLLocalizedLabelKey: CFStringRef; - pub static kCFURLLocalizedNameKey: CFStringRef; - pub static kCFURLLocalizedTypeDescriptionKey: CFStringRef; - pub static kCFURLNameKey: CFStringRef; - pub static kCFURLParentDirectoryURLKey: CFStringRef; - pub static kCFURLPreferredIOBlockSizeKey: CFStringRef; - pub static kCFURLTypeIdentifierKey: CFStringRef; - pub static kCFURLVolumeIdentifierKey: CFStringRef; - pub static kCFURLVolumeURLKey: CFStringRef; - - #[cfg(feature="mac_os_10_8_features")] - #[cfg_attr(feature = "mac_os_10_7_support", linkage = "extern_weak")] - pub static kCFURLIsExcludedFromBackupKey: CFStringRef; - pub static kCFURLFileResourceTypeKey: CFStringRef; - - /* Creating a CFURL */ - pub fn CFURLCopyAbsoluteURL(anURL: CFURLRef) -> CFURLRef; - //fn CFURLCreateAbsoluteURLWithBytes - //fn CFURLCreateByResolvingBookmarkData - //fn CFURLCreateCopyAppendingPathComponent - //fn CFURLCreateCopyAppendingPathExtension - //fn CFURLCreateCopyDeletingLastPathComponent - //fn CFURLCreateCopyDeletingPathExtension - pub fn CFURLCreateFilePathURL(allocator: CFAllocatorRef, url: CFURLRef, error: *mut CFErrorRef) -> CFURLRef; - //fn CFURLCreateFileReferenceURL - pub fn CFURLCreateFromFileSystemRepresentation(allocator: CFAllocatorRef, buffer: *const u8, bufLen: CFIndex, isDirectory: Boolean) -> CFURLRef; - //fn CFURLCreateFromFileSystemRepresentationRelativeToBase - //fn CFURLCreateFromFSRef - pub fn CFURLCreateWithBytes(allocator: CFAllocatorRef, URLBytes: *const u8, length: CFIndex, encoding: CFStringEncoding, baseURL: CFURLRef) -> CFURLRef; - pub fn CFURLCreateWithFileSystemPath(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean) -> CFURLRef; - pub fn CFURLCreateWithFileSystemPathRelativeToBase(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean, baseURL: CFURLRef) -> CFURLRef; - //fn CFURLCreateWithString(allocator: CFAllocatorRef, urlString: CFStringRef, - // baseURL: CFURLRef) -> CFURLRef; - - /* Accessing the Parts of a URL */ - pub fn CFURLCanBeDecomposed(anURL: CFURLRef) -> Boolean; - pub fn CFURLCopyFileSystemPath(anURL: CFURLRef, pathStyle: CFURLPathStyle) -> CFStringRef; - pub fn CFURLCopyFragment(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; - pub fn CFURLCopyHostName(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyLastPathComponent(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyNetLocation(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyParameterString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; - pub fn CFURLCopyPassword(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyPath(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyPathExtension(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyQueryString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; - pub fn CFURLCopyResourceSpecifier(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyScheme(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLCopyStrictPath(anURL: CFURLRef, isAbsolute: *mut Boolean) -> CFStringRef; - pub fn CFURLCopyUserName(anURL: CFURLRef) -> CFStringRef; - pub fn CFURLGetPortNumber(anURL: CFURLRef) -> SInt32; - pub fn CFURLHasDirectoryPath(anURL: CFURLRef) -> Boolean; - - /* Converting URLs to Other Representations */ - //fn CFURLCreateData(allocator: CFAllocatorRef, url: CFURLRef, - // encoding: CFStringEncoding, escapeWhitespace: bool) -> CFDataRef; - //fn CFURLCreateStringByAddingPercentEscapes - //fn CFURLCreateStringByReplacingPercentEscapes - //fn CFURLCreateStringByReplacingPercentEscapesUsingEncoding - pub fn CFURLGetFileSystemRepresentation(anURL: CFURLRef, resolveAgainstBase: Boolean, buffer: *mut u8, maxBufLen: CFIndex) -> Boolean; - - //fn CFURLGetFSRef - pub fn CFURLGetString(anURL: CFURLRef) -> CFStringRef; - - /* Getting URL Properties */ - //fn CFURLGetBaseURL(anURL: CFURLRef) -> CFURLRef; - pub fn CFURLGetBytes(anURL: CFURLRef, buffer: *mut u8, bufferLength: CFIndex) -> CFIndex; - //fn CFURLGetByteRangeForComponent - pub fn CFURLGetTypeID() -> CFTypeID; - //fn CFURLResourceIsReachable - - /* Getting and Setting File System Resource Properties */ - pub fn CFURLClearResourcePropertyCache(url: CFURLRef); - //fn CFURLClearResourcePropertyCacheForKey - //fn CFURLCopyResourcePropertiesForKeys - //fn CFURLCopyResourcePropertyForKey - //fn CFURLCreateResourcePropertiesForKeysFromBookmarkData - //fn CFURLCreateResourcePropertyForKeyFromBookmarkData - //fn CFURLSetResourcePropertiesForKeys - pub fn CFURLSetResourcePropertyForKey(url: CFURLRef, key: CFStringRef, value: CFTypeRef, error: *mut CFErrorRef) -> Boolean; - //fn CFURLSetTemporaryResourcePropertyForKey - - /* Working with Bookmark Data */ - //fn CFURLCreateBookmarkData - //fn CFURLCreateBookmarkDataFromAliasRecord - //fn CFURLCreateBookmarkDataFromFile - //fn CFURLWriteBookmarkDataToFile - //fn CFURLStartAccessingSecurityScopedResource - //fn CFURLStopAccessingSecurityScopedResource -} - -#[test] -#[cfg(feature="mac_os_10_8_features")] -fn can_see_excluded_from_backup_key() { - let _ = unsafe { kCFURLIsExcludedFromBackupKey }; -} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/.cargo-checksum.json b/third_party/cargo/vendor/core-foundation-sys-0.8.2/.cargo-checksum.json new file mode 100644 index 0000000..3b04722 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"380a7141d91af6d200eece8c518d2b60e98818025302982d733e459ccf2cde19","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","build.rs":"9433ed3b20cc99e716dda4c6d8507c29bc04882544cbbea8d4e48ba80fd0fa12","src/array.rs":"40c305658e16b07d86353a5ad34e7b5fb98720f19cc2b5173360d6a61ce2642f","src/attributed_string.rs":"48c2d161d6f54136ae895a9f52efad1f831718ea331b875d25498039158a2d51","src/base.rs":"7b21281e9a01903c79a7891ee4e1865a11504b281b468815d1a3838e1744a3c2","src/bundle.rs":"be1ce281cb415b3a46a0f961e5a30ded5d295a09c0a4c7f27efa6721e2516c69","src/characterset.rs":"a10bbb42ddc74b3dc50b43ae6a50cc9d9a1cd08b975a1ce1b092be4bf64448a6","src/data.rs":"7cf4ddbc62635434fd3552739ffae9dde5f5d34f0ad0bb818068d3ac26403784","src/date.rs":"c064ee4c3ebd1927532c34871e2e41179d6e3c3e400f6b409a18ad9e2337477f","src/dictionary.rs":"3327a6f90f1e0db5e3fde1973e2df4143ca896716a816d03f2b17c8e988c5159","src/error.rs":"6205ebeb7631daa8bcd560862b6daa10f640c8c117ce5f6f7184f268dcbcb42a","src/filedescriptor.rs":"49580654b657811fade7adaa256f5f895cb011c9baa4731e2f44a6ec7fdba235","src/lib.rs":"f815234d32327532da600f47e9a006550d8993dcd695b803d0660316899f9319","src/messageport.rs":"e9227d5907cba8e29cdeea41bcb3ae5c7840220442953ab19aace31a84542f47","src/number.rs":"f28040accfbbec99c4e55f411facac7cde4ad89298af2d7d907312f18e4263bf","src/propertylist.rs":"7ec928438826c4ce40befedf3de0a37c8ecbc0fc17896dfa629d5864000b2cfe","src/runloop.rs":"26ca33e2472d191f583e01c24e8cd262f54de8b542fbe7278f33ab08b2925794","src/set.rs":"116c2f18008bfbeecac570d366dbd95b8fe5b9373e3e1bdd2c1d588314d776c5","src/string.rs":"ef2c408bf1fcea5d9106329fc48d659aabbdbca05eb121dfa27a221829bc4b89","src/timezone.rs":"c7dd9557646b7ff2bfd6a98bf92142b8304125b4e78dd651b687abc8da191159","src/url.rs":"4358f756ed3d5e9afd5a7f3e2e9115adc6133b47dc7ce59d6ebb32c6610b0e8f","src/uuid.rs":"82f75efa73d0842dff2e13d299c166c6593a77fcb69c4b7629a2df1c17ae507d"},"package":"ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/BUILD.bazel b/third_party/cargo/vendor/core-foundation-sys-0.8.2/BUILD.bazel new file mode 100644 index 0000000..a7c392b --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/BUILD.bazel @@ -0,0 +1,55 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "build-script-build" with type "custom-build" omitted + +rust_library( + name = "core_foundation_sys", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.8.2", + # buildifier: leave-alone + deps = [ + ], +) diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/Cargo.toml b/third_party/cargo/vendor/core-foundation-sys-0.8.2/Cargo.toml new file mode 100644 index 0000000..51956da --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-foundation-sys" +version = "0.8.2" +authors = ["The Servo Project Developers"] +build = "build.rs" +description = "Bindings to Core Foundation for macOS" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" + +[dependencies] + +[features] +mac_os_10_7_support = [] +mac_os_10_8_features = [] diff --git a/third_party/cargo/vendor/core-foundation-0.6.4/LICENSE-APACHE b/third_party/cargo/vendor/core-foundation-sys-0.8.2/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/core-foundation-0.6.4/LICENSE-APACHE rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/LICENSE-APACHE diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/LICENSE-MIT b/third_party/cargo/vendor/core-foundation-sys-0.8.2/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/LICENSE-MIT rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/LICENSE-MIT diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/build.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/build.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/build.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/build.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/array.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/array.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/array.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/array.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/attributed_string.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/attributed_string.rs new file mode 100644 index 0000000..c91bf5b --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/attributed_string.rs @@ -0,0 +1,55 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; +use base::{CFAllocatorRef, CFTypeRef, CFIndex, CFRange, CFTypeID}; +use string::CFStringRef; +use dictionary::CFDictionaryRef; + +#[repr(C)] +pub struct __CFAttributedString(c_void); + +pub type CFAttributedStringRef = *const __CFAttributedString; +pub type CFMutableAttributedStringRef = *const __CFAttributedString; + +extern { + /* CFAttributedString */ + + pub fn CFAttributedStringCreate( + allocator: CFAllocatorRef, + str: CFStringRef, + attributes: CFDictionaryRef, + ) -> CFAttributedStringRef; + + pub fn CFAttributedStringGetLength(astr: CFAttributedStringRef) -> CFIndex; + + pub fn CFAttributedStringGetTypeID() -> CFTypeID; + + /* CFMutableAttributedString */ + + pub fn CFAttributedStringCreateMutableCopy( + allocator: CFAllocatorRef, max_length: CFIndex, astr: CFAttributedStringRef + ) -> CFMutableAttributedStringRef; + + pub fn CFAttributedStringCreateMutable( + allocator: CFAllocatorRef, + max_length: CFIndex, + ) -> CFMutableAttributedStringRef; + + pub fn CFAttributedStringReplaceString( + astr: CFMutableAttributedStringRef, range: CFRange, replacement: CFStringRef); + + pub fn CFAttributedStringSetAttribute( + astr: CFMutableAttributedStringRef, + range: CFRange, + attr_name: CFStringRef, + value: CFTypeRef, + ); + +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/base.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/base.rs new file mode 100644 index 0000000..52a166f --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/base.rs @@ -0,0 +1,157 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp::Ordering; +use std::os::raw::{c_uint, c_void, c_int}; +use string::CFStringRef; + +pub type Boolean = u8; +pub type mach_port_t = c_uint; +pub type CFAllocatorRef = *const c_void; +pub type CFNullRef = *const c_void; +pub type CFTypeRef = *const c_void; +pub type OSStatus = i32; +pub type SInt32 = c_int; +pub type CFTypeID = usize; +pub type CFOptionFlags = usize; +pub type CFHashCode = usize; +pub type CFIndex = isize; + +#[repr(isize)] +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CFComparisonResult { + LessThan = -1, + EqualTo = 0, + GreaterThan = 1, +} + +impl Into for CFComparisonResult { + fn into(self) -> Ordering { + match self { + CFComparisonResult::LessThan => Ordering::Less, + CFComparisonResult::EqualTo => Ordering::Equal, + CFComparisonResult::GreaterThan => Ordering::Greater + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFRange { + pub location: CFIndex, + pub length: CFIndex +} + +// for back-compat +impl CFRange { + pub fn init(location: CFIndex, length: CFIndex) -> CFRange { + CFRange { + location: location, + length: length, + } + } +} + +pub type CFAllocatorRetainCallBack = extern "C" fn(info: *mut c_void) -> *mut c_void; +pub type CFAllocatorReleaseCallBack = extern "C" fn(info: *mut c_void); +pub type CFAllocatorCopyDescriptionCallBack = extern "C" fn(info: *mut c_void) -> CFStringRef; +pub type CFAllocatorAllocateCallBack = extern "C" fn(allocSize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; +pub type CFAllocatorReallocateCallBack = extern "C" fn(ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; +pub type CFAllocatorDeallocateCallBack = extern "C" fn(ptr: *mut c_void, info: *mut c_void); +pub type CFAllocatorPreferredSizeCallBack = extern "C" fn(size: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> CFIndex; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFAllocatorContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: Option, + pub release: Option, + pub copyDescription: Option, + pub allocate: Option, + pub reallocate: Option, + pub deallocate: Option, + pub preferredSize: Option +} + +/// Trait for all types which are Core Foundation reference types. +pub trait TCFTypeRef { + fn as_void_ptr(&self) -> *const c_void; + + unsafe fn from_void_ptr(ptr: *const c_void) -> Self; +} + +impl TCFTypeRef for *const T { + fn as_void_ptr(&self) -> *const c_void { + (*self) as *const c_void + } + + unsafe fn from_void_ptr(ptr: *const c_void) -> Self { + ptr as *const T + } +} + +impl TCFTypeRef for *mut T { + fn as_void_ptr(&self) -> *const c_void { + (*self) as *const T as *const c_void + } + + unsafe fn from_void_ptr(ptr: *const c_void) -> Self { + ptr as *const T as *mut T + } +} + +/// Constant used by some functions to indicate failed searches. +pub static kCFNotFound: CFIndex = -1; + +extern { + /* + * CFBase.h + */ + + /* CFAllocator Reference */ + + pub static kCFAllocatorDefault: CFAllocatorRef; + pub static kCFAllocatorSystemDefault: CFAllocatorRef; + pub static kCFAllocatorMalloc: CFAllocatorRef; + pub static kCFAllocatorMallocZone: CFAllocatorRef; + pub static kCFAllocatorNull: CFAllocatorRef; + pub static kCFAllocatorUseContext: CFAllocatorRef; + + pub fn CFAllocatorCreate(allocator: CFAllocatorRef, context: *mut CFAllocatorContext) -> CFAllocatorRef; + pub fn CFAllocatorAllocate(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> *mut c_void; + pub fn CFAllocatorDeallocate(allocator: CFAllocatorRef, ptr: *mut c_void); + pub fn CFAllocatorGetPreferredSizeForSize(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> CFIndex; + pub fn CFAllocatorReallocate(allocator: CFAllocatorRef, ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags) -> *mut c_void; + pub fn CFAllocatorGetDefault() -> CFAllocatorRef; + pub fn CFAllocatorSetDefault(allocator: CFAllocatorRef); + pub fn CFAllocatorGetContext(allocator: CFAllocatorRef, context: *mut CFAllocatorContext); + pub fn CFAllocatorGetTypeID() -> CFTypeID; + + /* CFNull Reference */ + + pub static kCFNull: CFNullRef; + + /* CFType Reference */ + + //fn CFCopyTypeIDDescription + //fn CFGetAllocator + pub fn CFCopyDescription(cf: CFTypeRef) -> CFStringRef; + pub fn CFEqual(cf1: CFTypeRef, cf2: CFTypeRef) -> Boolean; + pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex; + pub fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID; + pub fn CFHash(cf: CFTypeRef) -> CFHashCode; + //fn CFMakeCollectable + pub fn CFRelease(cf: CFTypeRef); + pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef; + pub fn CFShow(obj: CFTypeRef); + + /* Base Utilities Reference */ + // N.B. Some things missing here. +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/bundle.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/bundle.rs new file mode 100644 index 0000000..45c6429 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/bundle.rs @@ -0,0 +1,38 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use base::{CFTypeID, CFAllocatorRef}; +use url::CFURLRef; +use dictionary::CFDictionaryRef; +use string::CFStringRef; + +#[repr(C)] +pub struct __CFBundle(c_void); + +pub type CFBundleRef = *mut __CFBundle; + +extern { + /* + * CFBundle.h + */ + pub fn CFBundleCreate(allocator: CFAllocatorRef, bundleURL: CFURLRef) -> CFBundleRef; + + pub fn CFBundleGetBundleWithIdentifier(bundleID: CFStringRef) -> CFBundleRef; + pub fn CFBundleGetFunctionPointerForName(bundle: CFBundleRef, function_name: CFStringRef) -> *const c_void; + pub fn CFBundleGetMainBundle() -> CFBundleRef; + pub fn CFBundleGetInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; + + pub fn CFBundleGetTypeID() -> CFTypeID; + pub fn CFBundleCopyExecutableURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopyPrivateFrameworksURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopySharedSupportURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopyBundleURL(bundle: CFBundleRef) -> CFURLRef; +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/characterset.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/characterset.rs new file mode 100644 index 0000000..6b347a5 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/characterset.rs @@ -0,0 +1,58 @@ +// Copyright 2019 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; +use base::{Boolean, CFAllocatorRef, CFIndex, CFRange, CFTypeID}; +use data::CFDataRef; +use string::{CFStringRef, UniChar}; + +pub type CFCharacterSetPredefinedSet = CFIndex; + +// Members of CFCharacterSetPredefinedSet enum +pub static kCFCharacterSetControl: CFCharacterSetPredefinedSet = 1; +pub static kCFCharacterSetWhitespace: CFCharacterSetPredefinedSet = 2; +pub static kCFCharacterSetWhitespaceAndNewline: CFCharacterSetPredefinedSet = 3; +pub static kCFCharacterSetDecimalDigit: CFCharacterSetPredefinedSet = 4; +pub static kCFCharacterSetLetter: CFCharacterSetPredefinedSet = 5; +pub static kCFCharacterSetLowercaseLetter: CFCharacterSetPredefinedSet = 6; +pub static kCFCharacterSetUppercaseLetter: CFCharacterSetPredefinedSet = 7; +pub static kCFCharacterSetNonBase: CFCharacterSetPredefinedSet = 8; +pub static kCFCharacterSetDecomposable: CFCharacterSetPredefinedSet = 9; +pub static kCFCharacterSetAlphaNumeric: CFCharacterSetPredefinedSet = 10; +pub static kCFCharacterSetPunctuation: CFCharacterSetPredefinedSet = 11; +pub static kCFCharacterSetIllegal: CFCharacterSetPredefinedSet = 12; +pub static kCFCharacterSetCapitalizedLetter: CFCharacterSetPredefinedSet = 13; +pub static kCFCharacterSetSymbol: CFCharacterSetPredefinedSet = 14; +pub static kCFCharacterSetNewline: CFCharacterSetPredefinedSet = 15; + +#[repr(C)] +pub struct __CFCharacterSet(c_void); + +pub type CFCharacterSetRef = *const __CFCharacterSet; +pub type CFMutableCharacterSetRef = *const __CFCharacterSet; + +extern { + pub fn CFCharacterSetGetTypeID() -> CFTypeID; + pub fn CFCharacterSetGetPredefined(theSetIdentifier: CFCharacterSetPredefinedSet) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateWithCharactersInRange(alloc: CFAllocatorRef, theRange: CFRange) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateWithCharactersInString(alloc: CFAllocatorRef, theString: CFStringRef) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateWithBitmapRepresentation(alloc: CFAllocatorRef, theData: CFDataRef) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateMutable(alloc: CFAllocatorRef) -> CFMutableCharacterSetRef; + pub fn CFCharacterSetCreateCopy(alloc: CFAllocatorRef, theSet: CFCharacterSetRef) -> CFCharacterSetRef; + pub fn CFCharacterSetCreateMutableCopy(alloc: CFAllocatorRef, theSet: CFCharacterSetRef) -> CFMutableCharacterSetRef; + pub fn CFCharacterSetIsCharacterMember(theSet: CFCharacterSetRef, theChar: UniChar) -> Boolean; + pub fn CFCharacterSetCreateBitmapRepresentation(alloc: CFAllocatorRef, theSet: CFCharacterSetRef) -> CFDataRef; + pub fn CFCharacterSetAddCharactersInRange(theSet: CFMutableCharacterSetRef, theRange: CFRange); + pub fn CFCharacterSetRemoveCharactersInRange(theSet: CFMutableCharacterSetRef, theRange: CFRange); + pub fn CFCharacterSetAddCharactersInString(theSet: CFMutableCharacterSetRef, theString: CFStringRef); + pub fn CFCharacterSetRemoveCharactersInString(theSet: CFMutableCharacterSetRef, theString: CFStringRef); + pub fn CFCharacterSetUnion(theSet: CFMutableCharacterSetRef, theOtherSet: CFCharacterSetRef); + pub fn CFCharacterSetIntersect(theSet: CFMutableCharacterSetRef, theOtherSet: CFCharacterSetRef); + pub fn CFCharacterSetInvert(theSet: CFMutableCharacterSetRef); +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/data.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/data.rs new file mode 100644 index 0000000..7a62c9b --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/data.rs @@ -0,0 +1,32 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use base::{CFAllocatorRef, CFTypeID, CFIndex, CFRange}; + +#[repr(C)] +pub struct __CFData(c_void); + +pub type CFDataRef = *const __CFData; + +extern { + /* + * CFData.h + */ + + pub fn CFDataCreate(allocator: CFAllocatorRef, + bytes: *const u8, length: CFIndex) -> CFDataRef; + //fn CFDataFind + pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8; + pub fn CFDataGetBytes(theData: CFDataRef, range: CFRange, buffer: *mut u8); + pub fn CFDataGetLength(theData: CFDataRef) -> CFIndex; + + pub fn CFDataGetTypeID() -> CFTypeID; +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/date.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/date.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/date.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/date.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/dictionary.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/dictionary.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/dictionary.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/dictionary.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/error.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/error.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/error.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/error.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/filedescriptor.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/filedescriptor.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/filedescriptor.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/filedescriptor.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/lib.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/lib.rs new file mode 100644 index 0000000..9b1056b --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/lib.rs @@ -0,0 +1,31 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals, improper_ctypes)] + +#![cfg_attr(all(feature="mac_os_10_7_support", feature="mac_os_10_8_features"), feature(linkage))] // back-compat requires weak linkage + +pub mod array; +pub mod attributed_string; +pub mod base; +pub mod bundle; +pub mod characterset; +pub mod data; +pub mod date; +pub mod dictionary; +pub mod error; +pub mod filedescriptor; +pub mod messageport; +pub mod number; +pub mod propertylist; +pub mod runloop; +pub mod set; +pub mod string; +pub mod timezone; +pub mod url; +pub mod uuid; diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/messageport.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/messageport.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/messageport.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/messageport.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/number.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/number.rs new file mode 100644 index 0000000..c056a24 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/number.rs @@ -0,0 +1,84 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use base::{CFAllocatorRef, CFTypeID, CFComparisonResult}; + +#[repr(C)] +pub struct __CFBoolean(c_void); + +pub type CFBooleanRef = *const __CFBoolean; + +pub type CFNumberType = u32; + +// members of enum CFNumberType +pub const kCFNumberSInt8Type: CFNumberType = 1; +pub const kCFNumberSInt16Type: CFNumberType = 2; +pub const kCFNumberSInt32Type: CFNumberType = 3; +pub const kCFNumberSInt64Type: CFNumberType = 4; +pub const kCFNumberFloat32Type: CFNumberType = 5; +pub const kCFNumberFloat64Type: CFNumberType = 6; +pub const kCFNumberCharType: CFNumberType = 7; +pub const kCFNumberShortType: CFNumberType = 8; +pub const kCFNumberIntType: CFNumberType = 9; +pub const kCFNumberLongType: CFNumberType = 10; +pub const kCFNumberLongLongType: CFNumberType = 11; +pub const kCFNumberFloatType: CFNumberType = 12; +pub const kCFNumberDoubleType: CFNumberType = 13; +pub const kCFNumberCFIndexType: CFNumberType = 14; +pub const kCFNumberNSIntegerType: CFNumberType = 15; +pub const kCFNumberCGFloatType: CFNumberType = 16; +pub const kCFNumberMaxType: CFNumberType = 16; + +// This is an enum due to zero-sized types warnings. +// For more details see https://github.com/rust-lang/rust/issues/27303 +pub enum __CFNumber {} + +pub type CFNumberRef = *const __CFNumber; + +extern { + /* + * CFNumber.h + */ + pub static kCFBooleanTrue: CFBooleanRef; + pub static kCFBooleanFalse: CFBooleanRef; + + pub fn CFBooleanGetTypeID() -> CFTypeID; + pub fn CFBooleanGetValue(boolean: CFBooleanRef) -> bool; + + pub fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *const c_void) + -> CFNumberRef; + //fn CFNumberGetByteSize + pub fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *mut c_void) -> bool; + pub fn CFNumberCompare(date: CFNumberRef, other: CFNumberRef, context: *mut c_void) -> CFComparisonResult; + pub fn CFNumberGetTypeID() -> CFTypeID; + pub fn CFNumberGetType(number: CFNumberRef) -> CFNumberType; +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn match_for_type_id_should_be_backwards_compatible() { + let type_id = kCFNumberFloat32Type; + // this is the old style of matching for static variables + match type_id { + vf64 if vf64 == kCFNumberFloat32Type => assert!(true), + _ => panic!("should not happen"), + }; + + // this is new new style of matching for consts + match type_id { + kCFNumberFloat32Type => assert!(true), + _ => panic!("should not happen"), + }; + } +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/propertylist.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/propertylist.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/propertylist.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/propertylist.rs diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/runloop.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/runloop.rs new file mode 100644 index 0000000..53035a2 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/runloop.rs @@ -0,0 +1,164 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use array::CFArrayRef; +use base::{Boolean, CFIndex, CFTypeID, CFAllocatorRef, CFOptionFlags, CFHashCode, mach_port_t}; +use date::{CFAbsoluteTime, CFTimeInterval}; +use string::CFStringRef; + +#[repr(C)] +pub struct __CFRunLoop(c_void); + +pub type CFRunLoopRef = *mut __CFRunLoop; + +#[repr(C)] +pub struct __CFRunLoopSource(c_void); + +pub type CFRunLoopSourceRef = *mut __CFRunLoopSource; + +#[repr(C)] +pub struct __CFRunLoopObserver(c_void); + +pub type CFRunLoopObserverRef = *mut __CFRunLoopObserver; + +// Reasons for CFRunLoopRunInMode() to Return +pub const kCFRunLoopRunFinished: i32 = 1; +pub const kCFRunLoopRunStopped: i32 = 2; +pub const kCFRunLoopRunTimedOut: i32 = 3; +pub const kCFRunLoopRunHandledSource: i32 = 4; + +// Run Loop Observer Activities +//typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { +pub type CFRunLoopActivity = CFOptionFlags; +pub const kCFRunLoopEntry: CFOptionFlags = 1 << 0; +pub const kCFRunLoopBeforeTimers: CFOptionFlags = 1 << 1; +pub const kCFRunLoopBeforeSources: CFOptionFlags = 1 << 2; +pub const kCFRunLoopBeforeWaiting: CFOptionFlags = 1 << 5; +pub const kCFRunLoopAfterWaiting: CFOptionFlags = 1 << 6; +pub const kCFRunLoopExit: CFOptionFlags = 1 << 7; +pub const kCFRunLoopAllActivities: CFOptionFlags = 0x0FFFFFFF; + +#[repr(C)] +pub struct CFRunLoopSourceContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, + pub equal: Option Boolean>, + pub hash: Option CFHashCode>, + pub schedule: Option, + pub cancel: Option, + pub perform: extern "C" fn (info: *const c_void), +} + +#[repr(C)] +pub struct CFRunLoopSourceContext1 { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, + pub equal: Option Boolean>, + pub hash: Option CFHashCode>, + // note that the following two fields are platform dependent in the C header, the ones here are for macOS + pub getPort: extern "C" fn (info: *mut c_void) -> mach_port_t, + pub perform: extern "C" fn (msg: *mut c_void, size: CFIndex, allocator: CFAllocatorRef, info: *mut c_void) -> *mut c_void, +} + +#[repr(C)] +pub struct CFRunLoopObserverContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, +} + +pub type CFRunLoopObserverCallBack = extern "C" fn (observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); + +#[repr(C)] +pub struct CFRunLoopTimerContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, +} + +pub type CFRunLoopTimerCallBack = extern "C" fn (timer: CFRunLoopTimerRef, info: *mut c_void); + +#[repr(C)] +pub struct __CFRunLoopTimer(c_void); + +pub type CFRunLoopTimerRef = *mut __CFRunLoopTimer; + +extern { + /* + * CFRunLoop.h + */ + pub static kCFRunLoopDefaultMode: CFStringRef; + pub static kCFRunLoopCommonModes: CFStringRef; + pub fn CFRunLoopGetTypeID() -> CFTypeID; + pub fn CFRunLoopGetCurrent() -> CFRunLoopRef; + pub fn CFRunLoopGetMain() -> CFRunLoopRef; + pub fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef; + pub fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef; + pub fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef); + pub fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime; + pub fn CFRunLoopRun(); + pub fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32; + pub fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean; + pub fn CFRunLoopWakeUp(rl: CFRunLoopRef); + pub fn CFRunLoopStop(rl: CFRunLoopRef); + // fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void)); + pub fn CFRunLoopContainsSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); + pub fn CFRunLoopRemoveSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); + pub fn CFRunLoopContainsObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopAddObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); + pub fn CFRunLoopRemoveObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); + pub fn CFRunLoopContainsTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + pub fn CFRunLoopRemoveTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + + pub fn CFRunLoopSourceGetTypeID() -> CFTypeID; + pub fn CFRunLoopSourceCreate(allocator: CFAllocatorRef, order: CFIndex, context: *mut CFRunLoopSourceContext) -> CFRunLoopSourceRef; + pub fn CFRunLoopSourceGetOrder(source: CFRunLoopSourceRef) -> CFIndex; + pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); + pub fn CFRunLoopSourceIsValid(source: CFRunLoopSourceRef) -> Boolean; + pub fn CFRunLoopSourceGetContext(source: CFRunLoopSourceRef, context: *mut CFRunLoopSourceContext); + pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); + + pub fn CFRunLoopObserverGetTypeID() -> CFTypeID; + pub fn CFRunLoopObserverCreate(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, callout: CFRunLoopObserverCallBack, context: *mut CFRunLoopObserverContext) -> CFRunLoopObserverRef; + // fn CFRunLoopObserverCreateWithHandler(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, block: void (^) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) -> CFRunLoopObserverRef; + pub fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags; + pub fn CFRunLoopObserverDoesRepeat(observer: CFRunLoopObserverRef) -> Boolean; + pub fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserverRef) -> CFIndex; + pub fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserverRef); + pub fn CFRunLoopObserverIsValid(observer: CFRunLoopObserverRef) -> Boolean; + pub fn CFRunLoopObserverGetContext(observer: CFRunLoopObserverRef, context: *mut CFRunLoopObserverContext); + + pub fn CFRunLoopTimerGetTypeID() -> CFTypeID; + pub fn CFRunLoopTimerCreate(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimerRef; + // fn CFRunLoopTimerCreateWithHandler(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, block: void (^) (CFRunLoopTimerRef timer)) -> CFRunLoopTimerRef; + pub fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime; + pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); + pub fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval; + pub fn CFRunLoopTimerDoesRepeat(timer: CFRunLoopTimerRef) -> Boolean; + pub fn CFRunLoopTimerGetOrder(timer: CFRunLoopTimerRef) -> CFIndex; + pub fn CFRunLoopTimerInvalidate(timer: CFRunLoopTimerRef); + pub fn CFRunLoopTimerIsValid(timer: CFRunLoopTimerRef) -> Boolean; + pub fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext); + pub fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval; + pub fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval); +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/set.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/set.rs new file mode 100644 index 0000000..a5cc1b1 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/set.rs @@ -0,0 +1,66 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use base::{CFAllocatorRef, CFIndex, CFTypeID, Boolean}; + +pub type CFSetApplierFunction = extern "C" fn (value: *const c_void, + context: *const c_void); +pub type CFSetRetainCallBack = *const u8; +pub type CFSetReleaseCallBack = *const u8; +pub type CFSetCopyDescriptionCallBack = *const u8; +pub type CFSetEqualCallBack = *const u8; +pub type CFSetHashCallBack = *const u8; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFSetCallBacks { + pub version: CFIndex, + pub retain: CFSetRetainCallBack, + pub release: CFSetReleaseCallBack, + pub copyDescription: CFSetCopyDescriptionCallBack, + pub equal: CFSetEqualCallBack, + pub hash: CFSetHashCallBack, +} + +#[repr(C)] +pub struct __CFSet(c_void); + +pub type CFSetRef = *const __CFSet; + +extern { + /* + * CFSet.h + */ + + pub static kCFTypeSetCallBacks: CFSetCallBacks; + + /* Creating Sets */ + pub fn CFSetCreate(allocator: CFAllocatorRef, values: *const *const c_void, numValues: CFIndex, + callBacks: *const CFSetCallBacks) -> CFSetRef; + pub fn CFSetCreateCopy(allocator: CFAllocatorRef, theSet: CFSetRef) -> CFSetRef; + + /* Examining a Set */ + pub fn CFSetContainsValue(theSet: CFSetRef, value: *const c_void) -> Boolean; + pub fn CFSetGetCount(theSet: CFSetRef) -> CFIndex; + pub fn CFSetGetCountOfValue(theSet: CFSetRef, value: *const c_void) -> CFIndex; + pub fn CFSetGetValue(theSet: CFSetRef, value: *const c_void) -> *const c_void; + pub fn CFSetGetValueIfPresent(theSet: CFSetRef, candidate: *const c_void, value: *mut *const c_void) -> Boolean; + pub fn CFSetGetValues(theSet: CFSetRef, values: *mut *const c_void); + + /* Applying a Function to Set Members */ + pub fn CFSetApplyFunction(theSet: CFSetRef, + applier: CFSetApplierFunction, + context: *const c_void); + + /* Getting the CFSet Type ID */ + pub fn CFSetGetTypeID() -> CFTypeID; +} + diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/string.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/string.rs new file mode 100644 index 0000000..8b92024 --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/string.rs @@ -0,0 +1,319 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::{c_char, c_ushort, c_void}; + +use base::{Boolean, CFOptionFlags, CFIndex, CFAllocatorRef, CFRange, CFTypeID}; + +pub type UniChar = c_ushort; + +// CFString.h + +pub type CFStringCompareFlags = CFOptionFlags; +//static kCFCompareCaseInsensitive: CFStringCompareFlags = 1; +//static kCFCompareBackwards: CFStringCompareFlags = 4; +//static kCFCompareAnchored: CFStringCompareFlags = 8; +//static kCFCompareNonliteral: CFStringCompareFlags = 16; +//static kCFCompareLocalized: CFStringCompareFlags = 32; +//static kCFCompareNumerically: CFStringCompareFlags = 64; +//static kCFCompareDiacriticInsensitive: CFStringCompareFlags = 128; +//static kCFCompareWidthInsensitive: CFStringCompareFlags = 256; +//static kCFCompareForcedOrdering: CFStringCompareFlags = 512; + +pub type CFStringEncoding = u32; + +// macOS built-in encodings. + +//static kCFStringEncodingMacRoman: CFStringEncoding = 0; +//static kCFStringEncodingWindowsLatin1: CFStringEncoding = 0x0500; +//static kCFStringEncodingISOLatin1: CFStringEncoding = 0x0201; +//static kCFStringEncodingNextStepLatin: CFStringEncoding = 0x0B01; +//static kCFStringEncodingASCII: CFStringEncoding = 0x0600; +//static kCFStringEncodingUnicode: CFStringEncoding = 0x0100; +pub static kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; +//static kCFStringEncodingNonLossyASCII: CFStringEncoding = 0x0BFF; + +//static kCFStringEncodingUTF16: CFStringEncoding = 0x0100; +//static kCFStringEncodingUTF16BE: CFStringEncoding = 0x10000100; +//static kCFStringEncodingUTF16LE: CFStringEncoding = 0x14000100; +//static kCFStringEncodingUTF32: CFStringEncoding = 0x0c000100; +//static kCFStringEncodingUTF32BE: CFStringEncoding = 0x18000100; +//static kCFStringEncodingUTF32LE: CFStringEncoding = 0x1c000100; + + +// CFStringEncodingExt.h + +pub type CFStringEncodings = CFIndex; + +// External encodings, except those defined above. +// Defined above: kCFStringEncodingMacRoman = 0 +//static kCFStringEncodingMacJapanese: CFStringEncoding = 1; +//static kCFStringEncodingMacChineseTrad: CFStringEncoding = 2; +//static kCFStringEncodingMacKorean: CFStringEncoding = 3; +//static kCFStringEncodingMacArabic: CFStringEncoding = 4; +//static kCFStringEncodingMacHebrew: CFStringEncoding = 5; +//static kCFStringEncodingMacGreek: CFStringEncoding = 6; +//static kCFStringEncodingMacCyrillic: CFStringEncoding = 7; +//static kCFStringEncodingMacDevanagari: CFStringEncoding = 9; +//static kCFStringEncodingMacGurmukhi: CFStringEncoding = 10; +//static kCFStringEncodingMacGujarati: CFStringEncoding = 11; +//static kCFStringEncodingMacOriya: CFStringEncoding = 12; +//static kCFStringEncodingMacBengali: CFStringEncoding = 13; +//static kCFStringEncodingMacTamil: CFStringEncoding = 14; +//static kCFStringEncodingMacTelugu: CFStringEncoding = 15; +//static kCFStringEncodingMacKannada: CFStringEncoding = 16; +//static kCFStringEncodingMacMalayalam: CFStringEncoding = 17; +//static kCFStringEncodingMacSinhalese: CFStringEncoding = 18; +//static kCFStringEncodingMacBurmese: CFStringEncoding = 19; +//static kCFStringEncodingMacKhmer: CFStringEncoding = 20; +//static kCFStringEncodingMacThai: CFStringEncoding = 21; +//static kCFStringEncodingMacLaotian: CFStringEncoding = 22; +//static kCFStringEncodingMacGeorgian: CFStringEncoding = 23; +//static kCFStringEncodingMacArmenian: CFStringEncoding = 24; +//static kCFStringEncodingMacChineseSimp: CFStringEncoding = 25; +//static kCFStringEncodingMacTibetan: CFStringEncoding = 26; +//static kCFStringEncodingMacMongolian: CFStringEncoding = 27; +//static kCFStringEncodingMacEthiopic: CFStringEncoding = 28; +//static kCFStringEncodingMacCentralEurRoman: CFStringEncoding = 29; +//static kCFStringEncodingMacVietnamese: CFStringEncoding = 30; +//static kCFStringEncodingMacExtArabic: CFStringEncoding = 31; +//static kCFStringEncodingMacSymbol: CFStringEncoding = 33; +//static kCFStringEncodingMacDingbats: CFStringEncoding = 34; +//static kCFStringEncodingMacTurkish: CFStringEncoding = 35; +//static kCFStringEncodingMacCroatian: CFStringEncoding = 36; +//static kCFStringEncodingMacIcelandic: CFStringEncoding = 37; +//static kCFStringEncodingMacRomanian: CFStringEncoding = 38; +//static kCFStringEncodingMacCeltic: CFStringEncoding = 39; +//static kCFStringEncodingMacGaelic: CFStringEncoding = 40; +//static kCFStringEncodingMacFarsi: CFStringEncoding = 0x8C; +//static kCFStringEncodingMacUkrainian: CFStringEncoding = 0x98; +//static kCFStringEncodingMacInuit: CFStringEncoding = 0xEC; +//static kCFStringEncodingMacVT100: CFStringEncoding = 0xFC; +//static kCFStringEncodingMacHFS: CFStringEncoding = 0xFF; +// Defined above: kCFStringEncodingISOLatin1 = 0x0201 +//static kCFStringEncodingISOLatin2: CFStringEncoding = 0x0202; +//static kCFStringEncodingISOLatin3: CFStringEncoding = 0x0203; +//static kCFStringEncodingISOLatin4: CFStringEncoding = 0x0204; +//static kCFStringEncodingISOLatinCyrillic: CFStringEncoding = 0x0205; +//static kCFStringEncodingISOLatinArabic: CFStringEncoding = 0x0206; +//static kCFStringEncodingISOLatinGreek: CFStringEncoding = 0x0207; +//static kCFStringEncodingISOLatinHebrew: CFStringEncoding = 0x0208; +//static kCFStringEncodingISOLatin5: CFStringEncoding = 0x0209; +//static kCFStringEncodingISOLatin6: CFStringEncoding = 0x020A; +//static kCFStringEncodingISOLatinThai: CFStringEncoding = 0x020B; +//static kCFStringEncodingISOLatin7: CFStringEncoding = 0x020D; +//static kCFStringEncodingISOLatin8: CFStringEncoding = 0x020E; +//static kCFStringEncodingISOLatin9: CFStringEncoding = 0x020F; +//static kCFStringEncodingISOLatin10: CFStringEncoding = 0x0210; +//static kCFStringEncodingDOSLatinUS: CFStringEncoding = 0x0400; +//static kCFStringEncodingDOSGreek: CFStringEncoding = 0x0405; +//static kCFStringEncodingDOSBalticRim: CFStringEncoding = 0x0406; +//static kCFStringEncodingDOSLatin1: CFStringEncoding = 0x0410; +//static kCFStringEncodingDOSGreek1: CFStringEncoding = 0x0411; +//static kCFStringEncodingDOSLatin2: CFStringEncoding = 0x0412; +//static kCFStringEncodingDOSCyrillic: CFStringEncoding = 0x0413; +//static kCFStringEncodingDOSTurkish: CFStringEncoding = 0x0414; +//static kCFStringEncodingDOSPortuguese: CFStringEncoding = 0x0415; +//static kCFStringEncodingDOSIcelandic: CFStringEncoding = 0x0416; +//static kCFStringEncodingDOSHebrew: CFStringEncoding = 0x0417; +//static kCFStringEncodingDOSCanadianFrench: CFStringEncoding = 0x0418; +//static kCFStringEncodingDOSArabic: CFStringEncoding = 0x0419; +//static kCFStringEncodingDOSNordic: CFStringEncoding = 0x041A; +//static kCFStringEncodingDOSRussian: CFStringEncoding = 0x041B; +//static kCFStringEncodingDOSGreek2: CFStringEncoding = 0x041C; +//static kCFStringEncodingDOSThai: CFStringEncoding = 0x041D; +//static kCFStringEncodingDOSJapanese: CFStringEncoding = 0x0420; +//static kCFStringEncodingDOSChineseSimplif: CFStringEncoding = 0x0421; +//static kCFStringEncodingDOSKorean: CFStringEncoding = 0x0422; +//static kCFStringEncodingDOSChineseTrad: CFStringEncoding = 0x0423; +// Defined above: kCFStringEncodingWindowsLatin1 = 0x0500 +//static kCFStringEncodingWindowsLatin2: CFStringEncoding = 0x0501; +//static kCFStringEncodingWindowsCyrillic: CFStringEncoding = 0x0502; +//static kCFStringEncodingWindowsGreek: CFStringEncoding = 0x0503; +//static kCFStringEncodingWindowsLatin5: CFStringEncoding = 0x0504; +//static kCFStringEncodingWindowsHebrew: CFStringEncoding = 0x0505; +//static kCFStringEncodingWindowsArabic: CFStringEncoding = 0x0506; +//static kCFStringEncodingWindowsBalticRim: CFStringEncoding = 0x0507; +//static kCFStringEncodingWindowsVietnamese: CFStringEncoding = 0x0508; +//static kCFStringEncodingWindowsKoreanJohab: CFStringEncoding = 0x0510; +// Defined above: kCFStringEncodingASCII = 0x0600 +//static kCFStringEncodingANSEL: CFStringEncoding = 0x0601; +//static kCFStringEncodingJIS_X0201_76: CFStringEncoding = 0x0620; +//static kCFStringEncodingJIS_X0208_83: CFStringEncoding = 0x0621; +//static kCFStringEncodingJIS_X0208_90: CFStringEncoding = 0x0622; +//static kCFStringEncodingJIS_X0212_90: CFStringEncoding = 0x0623; +//static kCFStringEncodingJIS_C6226_78: CFStringEncoding = 0x0624; +//static kCFStringEncodingShiftJIS_X0213: CFStringEncoding = 0x0628; +//static kCFStringEncodingShiftJIS_X0213_MenKuTen: CFStringEncoding = 0x0629; +//static kCFStringEncodingGB_2312_80: CFStringEncoding = 0x0630; +//static kCFStringEncodingGBK_95: CFStringEncoding = 0x0631; +//static kCFStringEncodingGB_18030_2000: CFStringEncoding = 0x0632; +//static kCFStringEncodingKSC_5601_87: CFStringEncoding = 0x0640; +//static kCFStringEncodingKSC_5601_92_Johab: CFStringEncoding = 0x0641; +//static kCFStringEncodingCNS_11643_92_P1: CFStringEncoding = 0x0651; +//static kCFStringEncodingCNS_11643_92_P2: CFStringEncoding = 0x0652; +//static kCFStringEncodingCNS_11643_92_P3: CFStringEncoding = 0x0653; +//static kCFStringEncodingISO_2022_JP: CFStringEncoding = 0x0820; +//static kCFStringEncodingISO_2022_JP_2: CFStringEncoding = 0x0821; +//static kCFStringEncodingISO_2022_JP_1: CFStringEncoding = 0x0822; +//static kCFStringEncodingISO_2022_JP_3: CFStringEncoding = 0x0823; +//static kCFStringEncodingISO_2022_CN: CFStringEncoding = 0x0830; +//static kCFStringEncodingISO_2022_CN_EXT: CFStringEncoding = 0x0831; +//static kCFStringEncodingISO_2022_KR: CFStringEncoding = 0x0840; +//static kCFStringEncodingEUC_JP: CFStringEncoding = 0x0920; +//static kCFStringEncodingEUC_CN: CFStringEncoding = 0x0930; +//static kCFStringEncodingEUC_TW: CFStringEncoding = 0x0931; +//static kCFStringEncodingEUC_KR: CFStringEncoding = 0x0940; +//static kCFStringEncodingShiftJIS: CFStringEncoding = 0x0A01; +//static kCFStringEncodingKOI8_R: CFStringEncoding = 0x0A02; +//static kCFStringEncodingBig5: CFStringEncoding = 0x0A03; +//static kCFStringEncodingMacRomanLatin1: CFStringEncoding = 0x0A04; +//static kCFStringEncodingHZ_GB_2312: CFStringEncoding = 0x0A05; +//static kCFStringEncodingBig5_HKSCS_1999: CFStringEncoding = 0x0A06; +//static kCFStringEncodingVISCII: CFStringEncoding = 0x0A07; +//static kCFStringEncodingKOI8_U: CFStringEncoding = 0x0A08; +//static kCFStringEncodingBig5_E: CFStringEncoding = 0x0A09; +// Defined above: kCFStringEncodingNextStepLatin = 0x0B01 +//static kCFStringEncodingNextStepJapanese: CFStringEncoding = 0x0B02; +//static kCFStringEncodingEBCDIC_US: CFStringEncoding = 0x0C01; +//static kCFStringEncodingEBCDIC_CP037: CFStringEncoding = 0x0C02; +//static kCFStringEncodingUTF7: CFStringEncoding = 0x04000100; +//static kCFStringEncodingUTF7_IMAP: CFStringEncoding = 0x0A10; +//static kCFStringEncodingShiftJIS_X0213_00: CFStringEncoding = 0x0628; /* Deprecated */ + +#[repr(C)] +pub struct __CFString(c_void); + +pub type CFStringRef = *const __CFString; + +extern { + /* + * CFString.h + */ + + // N.B. organized according to "Functions by task" in docs + + /* Creating a CFString */ + //fn CFSTR + //fn CFStringCreateArrayBySeparatingStrings + //fn CFStringCreateByCombiningStrings + //fn CFStringCreateCopy + //fn CFStringCreateFromExternalRepresentation + pub fn CFStringCreateWithBytes(alloc: CFAllocatorRef, + bytes: *const u8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: Boolean) + -> CFStringRef; + pub fn CFStringCreateWithBytesNoCopy(alloc: CFAllocatorRef, + bytes: *const u8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: Boolean, + contentsDeallocator: CFAllocatorRef) + -> CFStringRef; + //fn CFStringCreateWithCharacters + //fn CFStringCreateWithCharactersNoCopy + pub fn CFStringCreateWithCString(alloc: CFAllocatorRef, + cStr: *const c_char, + encoding: CFStringEncoding) + -> CFStringRef; + //fn CFStringCreateWithCStringNoCopy + //fn CFStringCreateWithFormat + //fn CFStringCreateWithFormatAndArguments + //fn CFStringCreateWithPascalString + //fn CFStringCreateWithPascalStringNoCopy + //fn CFStringCreateWithSubstring + + /* Searching Strings */ + //fn CFStringCreateArrayWithFindResults + //fn CFStringFind + //fn CFStringFindCharacterFromSet + //fn CFStringFindWithOptions + //fn CFStringFindWithOptionsAndLocale + //fn CFStringGetLineBounds + + /* Comparing Strings */ + //fn CFStringCompare + //fn CFStringCompareWithOptions + //fn CFStringCompareWithOptionsAndLocale + //fn CFStringHasPrefix + //fn CFStringHasSuffix + + /* Accessing Characters */ + //fn CFStringCreateExternalRepresentation + pub fn CFStringGetBytes(theString: CFStringRef, + range: CFRange, + encoding: CFStringEncoding, + lossByte: u8, + isExternalRepresentation: Boolean, + buffer: *mut u8, + maxBufLen: CFIndex, + usedBufLen: *mut CFIndex) + -> CFIndex; + //fn CFStringGetCharacterAtIndex + //fn CFStringGetCharacters + //fn CFStringGetCharactersPtr + //fn CFStringGetCharacterFromInlineBuffer + pub fn CFStringGetCString(theString: CFStringRef, + buffer: *mut c_char, + bufferSize: CFIndex, + encoding: CFStringEncoding) + -> Boolean; + pub fn CFStringGetCStringPtr(theString: CFStringRef, + encoding: CFStringEncoding) + -> *const c_char; + pub fn CFStringGetLength(theString: CFStringRef) -> CFIndex; + //fn CFStringGetPascalString + //fn CFStringGetPascalStringPtr + //fn CFStringGetRangeOfComposedCharactersAtIndex + //fn CFStringInitInlineBuffer + + /* Working With Hyphenation */ + //fn CFStringGetHyphenationLocationBeforeIndex + //fn CFStringIsHyphenationAvailableForLocale + + /* Working With Encodings */ + //fn CFStringConvertEncodingToIANACharSetName + //fn CFStringConvertEncodingToNSStringEncoding + //fn CFStringConvertEncodingToWindowsCodepage + //fn CFStringConvertIANACharSetNameToEncoding + //fn CFStringConvertNSStringEncodingToEncoding + //fn CFStringConvertWindowsCodepageToEncoding + //fn CFStringGetFastestEncoding + //fn CFStringGetListOfAvailableEncodings + //fn CFStringGetMaximumSizeForEncoding + //fn CFStringGetMostCompatibleMacStringEncoding + //fn CFStringGetNameOfEncoding + //fn CFStringGetSmallestEncoding + //fn CFStringGetSystemEncoding + //fn CFStringIsEncodingAvailable + + /* Getting Numeric Values */ + //fn CFStringGetDoubleValue + //fn CFStringGetIntValue + + /* Getting String Properties */ + //fn CFShowStr + pub fn CFStringGetTypeID() -> CFTypeID; + + /* String File System Representations */ + //fn CFStringCreateWithFileSystemRepresentation + //fn CFStringGetFileSystemRepresentation + //fn CFStringGetMaximumSizeOfFileSystemRepresentation + + /* Getting Paragraph Bounds */ + //fn CFStringGetParagraphBounds + + /* Managing Surrogates */ + //fn CFStringGetLongCharacterForSurrogatePair + //fn CFStringGetSurrogatePairForLongCharacter + //fn CFStringIsSurrogateHighCharacter + //fn CFStringIsSurrogateLowCharacter +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/timezone.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/timezone.rs new file mode 100644 index 0000000..0b279db --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/timezone.rs @@ -0,0 +1,29 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use base::{CFAllocatorRef, CFTypeID}; +use date::{CFTimeInterval, CFAbsoluteTime}; +use string::CFStringRef; + +#[repr(C)] +pub struct __CFTimeZone(c_void); + +pub type CFTimeZoneRef = *const __CFTimeZone; + +extern { + pub fn CFTimeZoneCopySystem() -> CFTimeZoneRef; + pub fn CFTimeZoneCopyDefault() -> CFTimeZoneRef; + pub fn CFTimeZoneCreateWithTimeIntervalFromGMT(allocator: CFAllocatorRef, interval: CFTimeInterval) -> CFTimeZoneRef; + pub fn CFTimeZoneGetSecondsFromGMT(tz: CFTimeZoneRef, time: CFAbsoluteTime) -> CFTimeInterval; + + pub fn CFTimeZoneGetTypeID() -> CFTypeID; + pub fn CFTimeZoneGetName(tz: CFTimeZoneRef) -> CFStringRef; +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/url.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/url.rs new file mode 100644 index 0000000..08e7bcd --- /dev/null +++ b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/url.rs @@ -0,0 +1,169 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +use base::{CFOptionFlags, CFIndex, CFAllocatorRef, Boolean, CFTypeID, CFTypeRef, SInt32}; +use data::CFDataRef; +use array::CFArrayRef; +use dictionary::CFDictionaryRef; +use string::{CFStringRef, CFStringEncoding}; +use error::CFErrorRef; + +#[repr(C)] +pub struct __CFURL(c_void); + +pub type CFURLRef = *const __CFURL; + +pub type CFURLBookmarkCreationOptions = CFOptionFlags; +pub type CFURLBookmarkResolutionOptions = CFOptionFlags; +pub type CFURLBookmarkFileCreationOptions = CFOptionFlags; + +pub type CFURLPathStyle = CFIndex; + +/* typedef CF_ENUM(CFIndex, CFURLPathStyle) */ +pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; +pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; +pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2; + +pub static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions = + (1u32 << 8) as usize; +pub static kCFURLBookmarkCreationMinimalBookmarkMask: CFURLBookmarkCreationOptions = + (1u32 << 9) as usize; +pub static kCFURLBookmarkCreationSuitableForBookmarkFile: CFURLBookmarkCreationOptions = + (1u32 << 10) as usize; +pub static kCFURLBookmarkCreationWithSecurityScope: CFURLBookmarkCreationOptions = + (1u32 << 11) as usize; +pub static kCFURLBookmarkCreationSecurityScopeAllowOnlyReadAccess: CFURLBookmarkCreationOptions = + (1u32 << 12) as usize; + +// TODO: there are a lot of missing keys and constants. Add if you are bored or need them. + +extern { + /* + * CFURL.h + */ + + /* Common File System Resource Keys */ + pub static kCFURLAttributeModificationDateKey: CFStringRef; + pub static kCFURLContentAccessDateKey: CFStringRef; + pub static kCFURLContentModificationDateKey: CFStringRef; + pub static kCFURLCreationDateKey: CFStringRef; + pub static kCFURLFileResourceIdentifierKey: CFStringRef; + pub static kCFURLFileSecurityKey: CFStringRef; + pub static kCFURLHasHiddenExtensionKey: CFStringRef; + pub static kCFURLIsDirectoryKey: CFStringRef; + pub static kCFURLIsExecutableKey: CFStringRef; + pub static kCFURLIsHiddenKey: CFStringRef; + pub static kCFURLIsPackageKey: CFStringRef; + pub static kCFURLIsReadableKey: CFStringRef; + pub static kCFURLIsRegularFileKey: CFStringRef; + pub static kCFURLIsSymbolicLinkKey: CFStringRef; + pub static kCFURLIsSystemImmutableKey: CFStringRef; + pub static kCFURLIsUserImmutableKey: CFStringRef; + pub static kCFURLIsVolumeKey: CFStringRef; + pub static kCFURLIsWritableKey: CFStringRef; + pub static kCFURLLabelNumberKey: CFStringRef; + pub static kCFURLLinkCountKey: CFStringRef; + pub static kCFURLLocalizedLabelKey: CFStringRef; + pub static kCFURLLocalizedNameKey: CFStringRef; + pub static kCFURLLocalizedTypeDescriptionKey: CFStringRef; + pub static kCFURLNameKey: CFStringRef; + pub static kCFURLParentDirectoryURLKey: CFStringRef; + pub static kCFURLPreferredIOBlockSizeKey: CFStringRef; + pub static kCFURLTypeIdentifierKey: CFStringRef; + pub static kCFURLVolumeIdentifierKey: CFStringRef; + pub static kCFURLVolumeURLKey: CFStringRef; + + #[cfg(feature="mac_os_10_8_features")] + #[cfg_attr(feature = "mac_os_10_7_support", linkage = "extern_weak")] + pub static kCFURLIsExcludedFromBackupKey: CFStringRef; + pub static kCFURLFileResourceTypeKey: CFStringRef; + + /* Creating a CFURL */ + pub fn CFURLCopyAbsoluteURL(anURL: CFURLRef) -> CFURLRef; + pub fn CFURLCreateAbsoluteURLWithBytes(allocator: CFAllocatorRef, relativeURLBytes: *const u8, length: CFIndex, encoding: CFStringEncoding, baseURL: CFURLRef, useCompatibilityMode: Boolean) -> CFURLRef; + pub fn CFURLCreateByResolvingBookmarkData(allocator: CFAllocatorRef, bookmark: CFDataRef, options: CFURLBookmarkResolutionOptions, relativeToURL: CFURLRef, resourcePropertiesToInclude: CFArrayRef, isStale: *mut Boolean, error: *mut CFErrorRef) -> CFURLRef; + //fn CFURLCreateCopyAppendingPathComponent + //fn CFURLCreateCopyAppendingPathExtension + //fn CFURLCreateCopyDeletingLastPathComponent + //fn CFURLCreateCopyDeletingPathExtension + pub fn CFURLCreateFilePathURL(allocator: CFAllocatorRef, url: CFURLRef, error: *mut CFErrorRef) -> CFURLRef; + //fn CFURLCreateFileReferenceURL + pub fn CFURLCreateFromFileSystemRepresentation(allocator: CFAllocatorRef, buffer: *const u8, bufLen: CFIndex, isDirectory: Boolean) -> CFURLRef; + //fn CFURLCreateFromFileSystemRepresentationRelativeToBase + //fn CFURLCreateFromFSRef + pub fn CFURLCreateWithBytes(allocator: CFAllocatorRef, URLBytes: *const u8, length: CFIndex, encoding: CFStringEncoding, baseURL: CFURLRef) -> CFURLRef; + pub fn CFURLCreateWithFileSystemPath(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean) -> CFURLRef; + pub fn CFURLCreateWithFileSystemPathRelativeToBase(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean, baseURL: CFURLRef) -> CFURLRef; + //fn CFURLCreateWithString(allocator: CFAllocatorRef, urlString: CFStringRef, + // baseURL: CFURLRef) -> CFURLRef; + + /* Accessing the Parts of a URL */ + pub fn CFURLCanBeDecomposed(anURL: CFURLRef) -> Boolean; + pub fn CFURLCopyFileSystemPath(anURL: CFURLRef, pathStyle: CFURLPathStyle) -> CFStringRef; + pub fn CFURLCopyFragment(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyHostName(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyLastPathComponent(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyNetLocation(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyParameterString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyPassword(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyPath(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyPathExtension(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyQueryString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyResourceSpecifier(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyScheme(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyStrictPath(anURL: CFURLRef, isAbsolute: *mut Boolean) -> CFStringRef; + pub fn CFURLCopyUserName(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLGetPortNumber(anURL: CFURLRef) -> SInt32; + pub fn CFURLHasDirectoryPath(anURL: CFURLRef) -> Boolean; + + /* Converting URLs to Other Representations */ + //fn CFURLCreateData(allocator: CFAllocatorRef, url: CFURLRef, + // encoding: CFStringEncoding, escapeWhitespace: bool) -> CFDataRef; + //fn CFURLCreateStringByAddingPercentEscapes + //fn CFURLCreateStringByReplacingPercentEscapes + //fn CFURLCreateStringByReplacingPercentEscapesUsingEncoding + pub fn CFURLGetFileSystemRepresentation(anURL: CFURLRef, resolveAgainstBase: Boolean, buffer: *mut u8, maxBufLen: CFIndex) -> Boolean; + + //fn CFURLGetFSRef + pub fn CFURLGetString(anURL: CFURLRef) -> CFStringRef; + + /* Getting URL Properties */ + //fn CFURLGetBaseURL(anURL: CFURLRef) -> CFURLRef; + pub fn CFURLGetBytes(anURL: CFURLRef, buffer: *mut u8, bufferLength: CFIndex) -> CFIndex; + //fn CFURLGetByteRangeForComponent + pub fn CFURLGetTypeID() -> CFTypeID; + //fn CFURLResourceIsReachable + + /* Getting and Setting File System Resource Properties */ + pub fn CFURLClearResourcePropertyCache(url: CFURLRef); + //fn CFURLClearResourcePropertyCacheForKey + //fn CFURLCopyResourcePropertiesForKeys + //fn CFURLCopyResourcePropertyForKey + pub fn CFURLCreateResourcePropertiesForKeysFromBookmarkData(allocator: CFAllocatorRef, resourcePropertiesToReturn: CFArrayRef, bookmark: CFDataRef) -> CFDictionaryRef; + pub fn CFURLCreateResourcePropertyForKeyFromBookmarkData(allocator: CFAllocatorRef, resourcePropertyKey: CFStringRef, bookmark: CFDataRef) -> CFTypeRef; + //fn CFURLSetResourcePropertiesForKeys + pub fn CFURLSetResourcePropertyForKey(url: CFURLRef, key: CFStringRef, value: CFTypeRef, error: *mut CFErrorRef) -> Boolean; + //fn CFURLSetTemporaryResourcePropertyForKey + + /* Working with Bookmark Data */ + pub fn CFURLCreateBookmarkData(allocator: CFAllocatorRef, url: CFURLRef, options: CFURLBookmarkCreationOptions, resourcePropertiesToInclude: CFArrayRef, relativeToURL: CFURLRef, error: *mut CFErrorRef) -> CFDataRef; + pub fn CFURLCreateBookmarkDataFromAliasRecord(allocator: CFAllocatorRef, aliasRecordDataRef: CFDataRef) -> CFDataRef; + pub fn CFURLCreateBookmarkDataFromFile(allocator: CFAllocatorRef, fileURL: CFURLRef, errorRef: *mut CFErrorRef) -> CFDataRef; + pub fn CFURLWriteBookmarkDataToFile(bookmarkRef: CFDataRef, fileURL: CFURLRef, options: CFURLBookmarkFileCreationOptions, errorRef: *mut CFErrorRef) -> Boolean; + pub fn CFURLStartAccessingSecurityScopedResource(url: CFURLRef) -> Boolean; + pub fn CFURLStopAccessingSecurityScopedResource(url: CFURLRef); +} + +#[test] +#[cfg(feature="mac_os_10_8_features")] +fn can_see_excluded_from_backup_key() { + let _ = unsafe { kCFURLIsExcludedFromBackupKey }; +} diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/src/uuid.rs b/third_party/cargo/vendor/core-foundation-sys-0.8.2/src/uuid.rs similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/src/uuid.rs rename to third_party/cargo/vendor/core-foundation-sys-0.8.2/src/uuid.rs diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/.cargo-checksum.json b/third_party/cargo/vendor/core-graphics-0.17.3/.cargo-checksum.json deleted file mode 100644 index 1dd1131..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"ff714d37c339428ee9c8958414b52f0f49578de1001cd27e732b8cc965ad0326","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"4a45abeb1e684e30bb361dfa7db59189423348e18d310cbae694b7c8c57cd86a","src/base.rs":"5faaadaf17d93c370a20f358be6c3f12958ab7d3f99ccc634421e28758fec88b","src/color.rs":"4c8ec4ab828cbc1b2a1538a34a51f5b380927f2f1daf187dff6f732f57a43656","src/color_space.rs":"b3d7ee8a21703c789160867cb8eb2188bd1daa193e3d030f21adb6f1a6f872de","src/context.rs":"6b14ec712e5d0af4af6beb0cb1a998bf1262ec6ab6ad2b3efad9e0362ade83c9","src/data_provider.rs":"22614a6ce7f857dec33e6d2dc01261b71b1bc5d5609a54ee55e04c049670c072","src/display.rs":"5b04d1fded021fc1eecb89b6350a66f6668e802b51e75cf69892ca082257443c","src/event.rs":"f2ade1c2c112bae7bc4f5df1eda63c13d1c32e5db255228f139ce17fb37c1a4b","src/event_source.rs":"d55a4f5b5e62789325028febc51bbf54c74b15ab1a4e70c6ad749a2f9753e081","src/font.rs":"63b7e50243a56254c800421df586abee59aead84f735f7df838ae04693aedf4b","src/geometry.rs":"cdeb9624df601d235bcc34d46e35bea302079ce1e3668253356a618486693a9f","src/image.rs":"0af720ee020fb1c6a2f4b1ce49e3d27f8f21f0be6b81ba4b9c824f87564efa58","src/lib.rs":"9b9601462de1bbc806e881b2b42e86b16372cad8eeefe1a96b772a9f7329958d","src/path.rs":"c429afeaed999b02ac00f89a867b5fc64f1e223039079a4e0529306b734ff117","src/private.rs":"da3fd61338bab2d8e26aa5433b2e18ecd2a0a408c62e1ac2b33a0f87f2dad88a","src/sys.rs":"cc90b690f172da51a87ffb234f6e74a9f501c4f1630d7b51fa2d5846e80fc164","src/window.rs":"2f6c3dc958ae2c0c9e2fc5033300b96e60ed0abee9823ea1f03797d64df0911a"},"package":"56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/BUILD.bazel b/third_party/cargo/vendor/core-graphics-0.17.3/BUILD.bazel deleted file mode 100644 index 06728ba..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/BUILD.bazel +++ /dev/null @@ -1,58 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "core_graphics", - srcs = glob(["**/*.rs"]), - crate_features = [ - "default", - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.17.3", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", - "//third_party/cargo/vendor/core-foundation-0.6.4:core_foundation", - "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", - "//third_party/cargo/vendor/libc-0.2.71:libc", - ], -) diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/Cargo.toml b/third_party/cargo/vendor/core-graphics-0.17.3/Cargo.toml deleted file mode 100644 index e445401..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "core-graphics" -version = "0.17.3" -authors = ["The Servo Project Developers"] -description = "Bindings to Core Graphics for OS X" -homepage = "https://github.com/servo/core-graphics-rs" -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/core-foundation-rs" -[dependencies.bitflags] -version = "1.0" - -[dependencies.core-foundation] -version = "0.6" - -[dependencies.foreign-types] -version = "0.3.0" - -[dependencies.libc] -version = "0.2" - -[features] -default = [] -elcapitan = [] -highsierra = [] diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/README.md b/third_party/cargo/vendor/core-graphics-0.17.3/README.md deleted file mode 100644 index a23522d..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# core-graphics-rs - -[![Build Status](https://travis-ci.org/servo/core-graphics-rs.svg?branch=master)](https://travis-ci.org/servo/core-graphics-rs) diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/base.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/base.rs deleted file mode 100644 index e7b7a19..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/base.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// this file defines CGFloat, as well as stubbed data types. - -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] - -use libc; - -#[cfg(any(target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64"))] -pub type boolean_t = libc::c_int; -#[cfg(target_arch = "x86_64")] -pub type boolean_t = libc::c_uint; - -#[cfg(target_pointer_width = "64")] -pub type CGFloat = libc::c_double; -#[cfg(not(target_pointer_width = "64"))] -pub type CGFloat = libc::c_float; - -pub type CGError = libc::int32_t; - -pub const kCGImageAlphaNone: u32 = 0; -pub const kCGImageAlphaPremultipliedLast: u32 = 1; -pub const kCGImageAlphaPremultipliedFirst: u32 = 2; -pub const kCGImageAlphaLast: u32 = 3; -pub const kCGImageAlphaFirst: u32 = 4; -pub const kCGImageAlphaNoneSkipLast: u32 = 5; -pub const kCGImageAlphaNoneSkipFirst: u32 = 6; - -pub const kCGBitmapByteOrderDefault: u32 = (0 << 12); -pub const kCGBitmapByteOrder16Little: u32 = (1 << 12); -pub const kCGBitmapByteOrder32Little: u32 = (2 << 12); -pub const kCGBitmapByteOrder16Big: u32 = (3 << 12); -pub const kCGBitmapByteOrder32Big: u32 = (4 << 12); - -pub const kCGRenderingIntentDefault: u32 = 0; -pub const kCGRenderingIntentAbsoluteColorimetric: u32 = 1; -pub const kCGRenderingIntentRelativeColorimetric: u32 = 2; -pub const kCGRenderingIntentPerceptual: u32 = 3; -pub const kCGRenderingIntentSaturation: u32 = 4; - -#[cfg(target_endian = "big")] -pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Big; -#[cfg(target_endian = "big")] -pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Big; - -#[cfg(target_endian = "little")] -pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Little; -#[cfg(target_endian = "little")] -pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Little; diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/context.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/context.rs deleted file mode 100644 index 1d73c23..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/context.rs +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright 2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use base::CGFloat; -use color_space::CGColorSpace; -use core_foundation::base::{ToVoid, CFRelease, CFRetain, CFTypeID}; -use font::{CGFont, CGGlyph}; -use geometry::CGPoint; -use color::CGColor; -use path::CGPathRef; -use libc::{c_int, size_t}; -use std::os::raw::c_void; - -use std::cmp; -use std::ptr; -use std::slice; -use geometry::{CGAffineTransform, CGRect}; -use image::CGImage; -use foreign_types::{ForeignType, ForeignTypeRef}; - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGBlendMode { - Normal = 0, - Multiply, - Screen, - Overlay, - Darken, - Lighten, - ColorDodge, - ColorBurn, - SoftLight, - HardLight, - Difference, - Exclusion, - Hue, - Saturation, - Color, - Luminosity, - // 10.5 and up: - Clear, - Copy, - SourceIn, - SourceOut, - SourceAtop, - DestinationOver, - DestinationIn, - DestinationOut, - DestinationAtop, - Xor, - PlusDarker, - PlusLighter, -} - -#[repr(C)] -pub enum CGTextDrawingMode { - CGTextFill, - CGTextStroke, - CGTextFillStroke, - CGTextInvisible, - CGTextFillClip, - CGTextStrokeClip, - CGTextClip -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGContext; - fn drop = |cs| CFRelease(cs as *mut _); - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGContext; - pub struct CGContextRef; -} - -impl CGContext { - pub fn type_id() -> CFTypeID { - unsafe { - CGContextGetTypeID() - } - } - - pub fn create_bitmap_context(data: Option<*mut c_void>, - width: size_t, - height: size_t, - bits_per_component: size_t, - bytes_per_row: size_t, - space: &CGColorSpace, - bitmap_info: u32) - -> CGContext { - unsafe { - let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()), - width, - height, - bits_per_component, - bytes_per_row, - space.as_ptr(), - bitmap_info); - assert!(!result.is_null()); - Self::from_ptr(result) - } - } - - pub fn data(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - CGBitmapContextGetData(self.as_ptr()) as *mut u8, - (self.height() * self.bytes_per_row()) as usize) - } - } -} - -impl CGContextRef { - pub fn flush(&self) { - unsafe { - CGContextFlush(self.as_ptr()) - } - } - - pub fn width(&self) -> size_t { - unsafe { - CGBitmapContextGetWidth(self.as_ptr()) - } - } - - pub fn height(&self) -> size_t { - unsafe { - CGBitmapContextGetHeight(self.as_ptr()) - } - } - - pub fn bytes_per_row(&self) -> size_t { - unsafe { - CGBitmapContextGetBytesPerRow(self.as_ptr()) - } - } - - pub fn set_fill_color(&self, color: &CGColor) { - unsafe { - CGContextSetFillColorWithColor(self.as_ptr(), color.to_void()); - } - } - - pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { - unsafe { - CGContextSetRGBFillColor(self.as_ptr(), red, green, blue, alpha) - } - } - - pub fn set_gray_fill_color(&self, gray: CGFloat, alpha: CGFloat) { - unsafe { - CGContextSetGrayFillColor(self.as_ptr(), gray, alpha) - } - } - - pub fn set_blend_mode(&self, blend_mode: CGBlendMode) { - unsafe { - CGContextSetBlendMode(self.as_ptr(), blend_mode) - } - } - - pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) { - unsafe { - CGContextSetAllowsFontSmoothing(self.as_ptr(), allows_font_smoothing) - } - } - - pub fn set_font_smoothing_style(&self, style: i32) { - unsafe { - CGContextSetFontSmoothingStyle(self.as_ptr(), style as _); - } - } - - pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) { - unsafe { - CGContextSetShouldSmoothFonts(self.as_ptr(), should_smooth_fonts) - } - } - - pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) { - unsafe { - CGContextSetAllowsAntialiasing(self.as_ptr(), allows_antialiasing) - } - } - - pub fn set_should_antialias(&self, should_antialias: bool) { - unsafe { - CGContextSetShouldAntialias(self.as_ptr(), should_antialias) - } - } - - pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) { - unsafe { - CGContextSetAllowsFontSubpixelQuantization(self.as_ptr(), allows_font_subpixel_quantization) - } - } - - pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) { - unsafe { - CGContextSetShouldSubpixelQuantizeFonts(self.as_ptr(), should_subpixel_quantize_fonts) - } - } - - pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) { - unsafe { - CGContextSetAllowsFontSubpixelPositioning(self.as_ptr(), allows_font_subpixel_positioning) - } - } - - pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) { - unsafe { - CGContextSetShouldSubpixelPositionFonts(self.as_ptr(), should_subpixel_position_fonts) - } - } - - pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) { - unsafe { - CGContextSetTextDrawingMode(self.as_ptr(), mode) - } - } - - pub fn add_path(&self, path: &CGPathRef) { - unsafe { - CGContextAddPath(self.as_ptr(), path.as_ptr()); - } - } - - pub fn close_path(&self) { - unsafe { - CGContextClosePath(self.as_ptr()); - } - } - - pub fn fill_path(&self) { - unsafe { - CGContextFillPath(self.as_ptr()); - } - } - - pub fn fill_rect(&self, rect: CGRect) { - unsafe { - CGContextFillRect(self.as_ptr(), rect) - } - } - - pub fn draw_image(&self, rect: CGRect, image: &CGImage) { - unsafe { - CGContextDrawImage(self.as_ptr(), rect, image.as_ptr()); - } - } - - pub fn create_image(&self) -> Option { - let image = unsafe { CGBitmapContextCreateImage(self.as_ptr()) }; - if !image.is_null() { - Some(unsafe { CGImage::from_ptr(image) }) - } else { - None - } - } - - pub fn set_font(&self, font: &CGFont) { - unsafe { - CGContextSetFont(self.as_ptr(), font.as_ptr()) - } - } - - pub fn set_font_size(&self, size: CGFloat) { - unsafe { - CGContextSetFontSize(self.as_ptr(), size) - } - } - - pub fn set_text_matrix(&self, t: &CGAffineTransform) { - unsafe { - CGContextSetTextMatrix(self.as_ptr(), *t) - } - } - - pub fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) { - unsafe { - let count = cmp::min(glyphs.len(), positions.len()); - CGContextShowGlyphsAtPositions(self.as_ptr(), - glyphs.as_ptr(), - positions.as_ptr(), - count) - } - } - - pub fn save(&self) { - unsafe { - CGContextSaveGState(self.as_ptr()); - } - } - - pub fn restore(&self) { - unsafe { - CGContextRestoreGState(self.as_ptr()); - } - } - - pub fn translate(&self, tx: CGFloat, ty: CGFloat) { - unsafe { - CGContextTranslateCTM(self.as_ptr(), tx, ty); - } - } - - pub fn scale(&self, sx: CGFloat, sy: CGFloat) { - unsafe { - CGContextScaleCTM(self.as_ptr(), sx, sy); - } - } -} - -#[test] -fn create_bitmap_context_test() { - use geometry::*; - - let cs = CGColorSpace::create_device_rgb(); - let ctx = CGContext::create_bitmap_context(None, - 16, 8, - 8, 0, - &cs, - ::base::kCGImageAlphaPremultipliedLast); - ctx.set_rgb_fill_color(1.,0.,1.,1.); - ctx.fill_rect(CGRect::new(&CGPoint::new(0.,0.), &CGSize::new(8.,8.))); - let img = ctx.create_image().unwrap(); - assert_eq!(16, img.width()); - assert_eq!(8, img.height()); - assert_eq!(8, img.bits_per_component()); - assert_eq!(32, img.bits_per_pixel()); - let data = img.data(); - assert_eq!(255, data.bytes()[0]); - assert_eq!(0, data.bytes()[1]); - assert_eq!(255, data.bytes()[2]); - assert_eq!(255, data.bytes()[3]); -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - fn CGBitmapContextCreate(data: *mut c_void, - width: size_t, - height: size_t, - bitsPerComponent: size_t, - bytesPerRow: size_t, - space: ::sys::CGColorSpaceRef, - bitmapInfo: u32) - -> ::sys::CGContextRef; - fn CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void; - fn CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t; - fn CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t; - fn CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t; - fn CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef; - fn CGContextGetTypeID() -> CFTypeID; - fn CGContextFlush(c: ::sys::CGContextRef); - fn CGContextSetBlendMode(c: ::sys::CGContextRef, blendMode: CGBlendMode); - fn CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool); - fn CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool); - fn CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int); - fn CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool); - fn CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool); - fn CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef, - allowsFontSubpixelQuantization: bool); - fn CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef, - shouldSubpixelQuantizeFonts: bool); - fn CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef, - allowsFontSubpixelPositioning: bool); - fn CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef, - shouldSubpixelPositionFonts: bool); - fn CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode); - fn CGContextSetFillColorWithColor(c: ::sys::CGContextRef, color: *const c_void); - fn CGContextAddPath(c: ::sys::CGContextRef, path: ::sys::CGPathRef); - fn CGContextClosePath(c: ::sys::CGContextRef); - fn CGContextFillPath(c: ::sys::CGContextRef); - fn CGContextSetRGBFillColor(context: ::sys::CGContextRef, - red: CGFloat, - green: CGFloat, - blue: CGFloat, - alpha: CGFloat); - fn CGContextSetGrayFillColor(context: ::sys::CGContextRef, gray: CGFloat, alpha: CGFloat); - fn CGContextFillRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef); - fn CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef); - fn CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat); - fn CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform); - fn CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef, - glyphs: *const CGGlyph, - positions: *const CGPoint, - count: size_t); - - fn CGContextSaveGState(c: ::sys::CGContextRef); - fn CGContextRestoreGState(c: ::sys::CGContextRef); - fn CGContextTranslateCTM(c: ::sys::CGContextRef, tx: CGFloat, ty: CGFloat); - fn CGContextScaleCTM(c: ::sys::CGContextRef, sx: CGFloat, sy: CGFloat); -} - diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/display.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/display.rs deleted file mode 100644 index bb2eec3..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/display.rs +++ /dev/null @@ -1,671 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(non_upper_case_globals)] - -use libc; -use std::ptr; -use std::ops::Deref; - -pub use base::{CGError, boolean_t}; -pub use geometry::{CGRect, CGPoint, CGSize}; - -use core_foundation::string::{CFString, CFStringRef}; -use core_foundation::base::{CFRetain, TCFType}; -use image::CGImage; -use foreign_types::ForeignType; - -pub type CGDirectDisplayID = libc::uint32_t; -pub type CGWindowID = libc::uint32_t; - -pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID; - - -pub type CGWindowListOption = libc::uint32_t; - -pub const kCGWindowListOptionAll: CGWindowListOption = 0; -pub const kCGWindowListOptionOnScreenOnly: CGWindowListOption = 1 << 0; -pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1; -pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2; -pub const kCGWindowListOptionIncludingWindow: CGWindowListOption = 1 << 3; -pub const kCGWindowListExcludeDesktopElements: CGWindowListOption = 1 << 4; - -pub type CGWindowImageOption = libc::uint32_t; - -pub const kCGWindowImageDefault: CGWindowImageOption = 0; -pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0; -pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1; -pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2; -pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3; -pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4; - -pub const kDisplayModeValidFlag: u32 = 0x00000001; -pub const kDisplayModeSafeFlag: u32 = 0x00000002; -pub const kDisplayModeDefaultFlag: u32 = 0x00000004; -pub const kDisplayModeAlwaysShowFlag: u32 = 0x00000008; -pub const kDisplayModeNeverShowFlag: u32 = 0x00000080; -pub const kDisplayModeNotResizeFlag: u32 = 0x00000010; -pub const kDisplayModeRequiresPanFlag: u32 = 0x00000020; -pub const kDisplayModeInterlacedFlag: u32 = 0x00000040; -pub const kDisplayModeSimulscanFlag: u32 = 0x00000100; -pub const kDisplayModeBuiltInFlag: u32 = 0x00000400; -pub const kDisplayModeNotPresetFlag: u32 = 0x00000200; -pub const kDisplayModeStretchedFlag: u32 = 0x00000800; -pub const kDisplayModeNotGraphicsQualityFlag: u32 = 0x00001000; -pub const kDisplayModeValidateAgainstDisplay: u32 = 0x00002000; -pub const kDisplayModeTelevisionFlag: u32 = 0x00100000; -pub const kDisplayModeValidForMirroringFlag: u32 = 0x00200000; -pub const kDisplayModeAcceleratorBackedFlag: u32 = 0x00400000; -pub const kDisplayModeValidForHiResFlag: u32 = 0x00800000; -pub const kDisplayModeValidForAirPlayFlag: u32 = 0x01000000; -pub const kDisplayModeNativeFlag: u32 = 0x02000000; - -pub const kDisplayModeSafetyFlags: u32 = 0x00000007; - -pub const IO1BitIndexedPixels: &str = "P"; -pub const IO2BitIndexedPixels: &str = "PP"; -pub const IO4BitIndexedPixels: &str = "PPPP"; -pub const IO8BitIndexedPixels: &str = "PPPPPPPP"; -pub const IO16BitDirectPixels: &str = "-RRRRRGGGGGBBBBB"; -pub const IO32BitDirectPixels: &str = "--------RRRRRRRRGGGGGGGGBBBBBBBB"; -pub const kIO30BitDirectPixels: &str = "--RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB"; -pub const kIO64BitDirectPixels: &str = "-16R16G16B16"; -pub const kIO16BitFloatPixels: &str = "-16FR16FG16FB16"; -pub const kIO32BitFloatPixels: &str = "-32FR32FG32FB32"; -pub const IOYUV422Pixels: &str = "Y4U2V2"; -pub const IO8BitOverlayPixels: &str = "O8"; - - -pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent }; -pub use core_foundation::array::{ CFArray, CFArrayRef }; -pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex }; -pub use core_foundation::base::{ CFIndex, CFRelease, CFTypeRef }; - -pub type CGDisplayConfigRef = *mut libc::c_void; - -#[repr(u32)] -#[derive(Clone, Copy)] -pub enum CGConfigureOption { - ConfigureForAppOnly = 0, - ConfigureForSession = 1, - ConfigurePermanently = 2, -} - -#[derive(Copy, Clone, Debug)] -pub struct CGDisplay { - pub id: CGDirectDisplayID, -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGDisplayMode; - fn drop = CGDisplayModeRelease; - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGDisplayMode; - pub struct CGDisplayModeRef; -} - -impl CGDisplay { - #[inline] - pub fn new(id: CGDirectDisplayID) -> CGDisplay { - CGDisplay { id: id } - } - - /// Returns the the main display. - #[inline] - pub fn main() -> CGDisplay { - CGDisplay::new(unsafe { CGMainDisplayID() }) - } - - /// Returns the bounds of a display in the global display coordinate space. - #[inline] - pub fn bounds(&self) -> CGRect { - unsafe { CGDisplayBounds(self.id) } - } - - /// Returns information about a display's current configuration. - #[inline] - pub fn display_mode(&self) -> Option { - unsafe { - let mode_ref = CGDisplayCopyDisplayMode(self.id); - if !mode_ref.is_null() { - Some(CGDisplayMode::from_ptr(mode_ref)) - } else { - None - } - } - } - - /// Begins a new set of display configuration changes. - pub fn begin_configuration(&self) -> Result { - unsafe { - let mut config_ref: CGDisplayConfigRef = ptr::null_mut(); - let result = CGBeginDisplayConfiguration(&mut config_ref); - if result == 0 { - Ok(config_ref) - } else { - Err(result) - } - } - } - - /// Cancels a set of display configuration changes. - pub fn cancel_configuration(&self, config_ref: &CGDisplayConfigRef) -> Result<(), CGError> { - let result = unsafe { CGCancelDisplayConfiguration(*config_ref) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Completes a set of display configuration changes. - pub fn complete_configuration( - &self, - config_ref: &CGDisplayConfigRef, - option: CGConfigureOption, - ) -> Result<(), CGError> { - let result = unsafe { CGCompleteDisplayConfiguration(*config_ref, option) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Configures the display mode of a display. - pub fn configure_display_with_display_mode( - &self, - config_ref: &CGDisplayConfigRef, - display_mode: &CGDisplayMode, - ) -> Result<(), CGError> { - let result = unsafe { - CGConfigureDisplayWithDisplayMode( - *config_ref, - self.id, - display_mode.as_ptr(), - ptr::null(), - ) - }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Returns an image containing the contents of the specified display. - #[inline] - pub fn image(&self) -> Option { - unsafe { - let image_ref = CGDisplayCreateImage(self.id); - if !image_ref.is_null() { - Some(CGImage::from_ptr(image_ref)) - } else { - None - } - } - } - - /// Returns a composite image based on a dynamically generated list of - /// windows. - #[inline] - pub fn screenshot( - bounds: CGRect, - list_option: CGWindowListOption, - window_id: CGWindowID, - image_option: CGWindowImageOption, - ) -> Option { - unsafe { - let image_ref = CGWindowListCreateImage(bounds, list_option, window_id, image_option); - if !image_ref.is_null() { - Some(CGImage::from_ptr(image_ref)) - } else { - None - } - } - } - - /// Returns a composite image of the specified windows. - #[inline] - pub fn screenshot_from_windows( - bounds: CGRect, - windows: CFArray, - image_option: CGWindowImageOption, - ) -> Option { - unsafe { - let image_ref = CGWindowListCreateImageFromArray( - bounds, - windows.as_concrete_TypeRef(), - image_option, - ); - if !image_ref.is_null() { - Some(CGImage::from_ptr(image_ref)) - } else { - None - } - } - } - - /// Generates and returns information about the selected windows in the - /// current user session. - pub fn window_list_info( - option: CGWindowListOption, - relative_to_window: Option, - ) -> Option { - let relative_to_window = relative_to_window.unwrap_or(kCGNullWindowID); - let array_ref = unsafe { CGWindowListCopyWindowInfo(option, relative_to_window) }; - if array_ref != ptr::null() { - Some(unsafe { TCFType::wrap_under_create_rule(array_ref) }) - } else { - None - } - } - - /// Returns a Boolean value indicating whether a display is active. - #[inline] - pub fn is_active(&self) -> bool { - unsafe { CGDisplayIsActive(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is always in a - /// mirroring set. - #[inline] - pub fn is_always_in_mirror_set(&self) -> bool { - unsafe { CGDisplayIsAlwaysInMirrorSet(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is sleeping (and is - /// therefore not drawable.) - #[inline] - pub fn is_asleep(&self) -> bool { - unsafe { CGDisplayIsAsleep(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is built-in, such as - /// the internal display in portable systems. - #[inline] - pub fn is_builtin(&self) -> bool { - unsafe { CGDisplayIsBuiltin(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is in a hardware - /// mirroring set. - #[inline] - pub fn is_in_hw_mirror_set(&self) -> bool { - unsafe { CGDisplayIsInHWMirrorSet(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is in a mirroring set. - #[inline] - pub fn is_in_mirror_set(&self) -> bool { - unsafe { CGDisplayIsInMirrorSet(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is the main display. - #[inline] - pub fn is_main(&self) -> bool { - unsafe { CGDisplayIsMain(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is connected or online. - #[inline] - pub fn is_online(&self) -> bool { - unsafe { CGDisplayIsOnline(self.id) != 0 } - } - - /// Returns a boolean indicating whether Quartz is using OpenGL-based - /// window acceleration (Quartz Extreme) to render in a display. - #[inline] - pub fn uses_open_gl_acceleration(&self) -> bool { - unsafe { CGDisplayUsesOpenGLAcceleration(self.id) != 0 } - } - - /// Returns a boolean indicating whether a display is running in a stereo - /// graphics mode. - #[inline] - pub fn is_stereo(&self) -> bool { - unsafe { CGDisplayIsStereo(self.id) != 0 } - } - - /// For a secondary display in a mirroring set, returns the primary - /// display. - #[inline] - pub fn mirrors_display(&self) -> CGDirectDisplayID { - unsafe { CGDisplayMirrorsDisplay(self.id) } - } - - /// Returns the primary display in a hardware mirroring set. - #[inline] - pub fn primary_display(&self) -> CGDirectDisplayID { - unsafe { CGDisplayPrimaryDisplay(self.id) } - } - - /// Returns the rotation angle of a display in degrees. - #[inline] - pub fn rotation(&self) -> f64 { - unsafe { CGDisplayRotation(self.id) } - } - - /// Returns the width and height of a display in millimeters. - #[inline] - pub fn screen_size(&self) -> CGSize { - unsafe { CGDisplayScreenSize(self.id) } - } - - /// Returns the serial number of a display monitor. - #[inline] - pub fn serial_number(&self) -> u32 { - unsafe { CGDisplaySerialNumber(self.id) } - } - - /// Returns the logical unit number of a display. - #[inline] - pub fn unit_number(&self) -> u32 { - unsafe { CGDisplayUnitNumber(self.id) } - } - - /// Returns the vendor number of the specified display's monitor. - #[inline] - pub fn vendor_number(&self) -> u32 { - unsafe { CGDisplayVendorNumber(self.id) } - } - - /// Returns the model number of a display monitor. - #[inline] - pub fn model_number(&self) -> u32 { - unsafe { CGDisplayModelNumber(self.id) } - } - - /// Returns the display height in pixel units. - #[inline] - pub fn pixels_high(&self) -> u64 { - unsafe { CGDisplayPixelsHigh(self.id) as u64 } - } - - /// Returns the display width in pixel units. - #[inline] - pub fn pixels_wide(&self) -> u64 { - unsafe { CGDisplayPixelsWide(self.id) as u64 } - } - - /// Provides a list of displays that are active (or drawable). - #[inline] - pub fn active_displays() -> Result, CGError> { - let count = try!(CGDisplay::active_display_count()); - let mut buf: Vec = vec![0; count as usize]; - let result = - unsafe { CGGetActiveDisplayList(count as u32, buf.as_mut_ptr(), ptr::null_mut()) }; - if result == 0 { - Ok(buf) - } else { - Err(result) - } - } - - /// Provides count of displays that are active (or drawable). - #[inline] - pub fn active_display_count() -> Result { - let mut count: libc::uint32_t = 0; - let result = unsafe { CGGetActiveDisplayList(0, ptr::null_mut(), &mut count) }; - if result == 0 { - Ok(count as u32) - } else { - Err(result) - } - } - - /// Hides the mouse cursor, and increments the hide cursor count. - #[inline] - pub fn hide_cursor(&self) -> Result<(), CGError> { - let result = unsafe { CGDisplayHideCursor(self.id) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Decrements the hide cursor count, and shows the mouse cursor if the - /// count is 0. - #[inline] - pub fn show_cursor(&self) -> Result<(), CGError> { - let result = unsafe { CGDisplayShowCursor(self.id) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Moves the mouse cursor to a specified point relative to the display - /// origin (the upper-left corner of the display). - #[inline] - pub fn move_cursor_to_point(&self, point: CGPoint) -> Result<(), CGError> { - let result = unsafe { CGDisplayMoveCursorToPoint(self.id, point) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Moves the mouse cursor without generating events. - #[inline] - pub fn warp_mouse_cursor_position(point: CGPoint) -> Result<(), CGError> { - let result = unsafe { CGWarpMouseCursorPosition(point) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } - - /// Connects or disconnects the mouse and cursor while an application is - /// in the foreground. - #[inline] - pub fn associate_mouse_and_mouse_cursor_position(connected: bool) -> Result<(), CGError> { - let result = unsafe { CGAssociateMouseAndMouseCursorPosition(connected as boolean_t) }; - if result == 0 { - Ok(()) - } else { - Err(result) - } - } -} - -impl CGDisplayMode { - /// Returns all display modes for the specified display id. - pub fn all_display_modes( - display_id: CGDirectDisplayID, - options: CFDictionaryRef, - ) -> Option> { - let array_opt: Option = unsafe { - let array_ref = CGDisplayCopyAllDisplayModes(display_id, options); - if array_ref != ptr::null() { - Some(CFArray::wrap_under_create_rule(array_ref)) - } else { - None - } - }; - match array_opt { - Some(modes) => { - let vec: Vec = modes - .into_iter() - .map(|value0| { - let x = *value0.deref() as *mut ::sys::CGDisplayMode; - unsafe { CGDisplayMode::from_ptr(x) } - }).collect(); - Some(vec) - } - None => None, - } - } - - /// Returns the height of the specified display mode. - #[inline] - pub fn height(&self) -> u64 { - unsafe { CGDisplayModeGetHeight(self.as_ptr()) as u64 } - } - - /// Returns the width of the specified display mode. - #[inline] - pub fn width(&self) -> u64 { - unsafe { CGDisplayModeGetWidth(self.as_ptr()) as u64 } - } - - /// Returns the pixel height of the specified display mode. - #[inline] - pub fn pixel_height(&self) -> u64 { - unsafe { CGDisplayModeGetPixelHeight(self.as_ptr()) as u64 } - } - - /// Returns the pixel width of the specified display mode. - #[inline] - pub fn pixel_width(&self) -> u64 { - unsafe { CGDisplayModeGetPixelWidth(self.as_ptr()) as u64 } - } - - #[inline] - pub fn refresh_rate(&self) -> f64 { - unsafe { CGDisplayModeGetRefreshRate(self.as_ptr()) } - } - - /// Returns the I/O Kit flags of the specified display mode. - #[inline] - pub fn io_flags(&self) -> u32 { - unsafe { CGDisplayModeGetIOFlags(self.as_ptr()) as u32 } - } - - /// Returns the pixel encoding of the specified display mode. - #[inline] - pub fn pixel_encoding(&self) -> CFString { - unsafe { CFString::wrap_under_create_rule(CGDisplayModeCopyPixelEncoding(self.as_ptr())) } - } - - /// Returns the number of bits per pixel of the specified display mode. - pub fn bit_depth(&self) -> usize { - let pixel_encoding = self.pixel_encoding().to_string(); - // my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels - // are made up and possibly non-sensical - if pixel_encoding.eq_ignore_ascii_case(kIO32BitFloatPixels) { - 96 - } else if pixel_encoding.eq_ignore_ascii_case(kIO64BitDirectPixels) { - 64 - } else if pixel_encoding.eq_ignore_ascii_case(kIO16BitFloatPixels) { - 48 - } else if pixel_encoding.eq_ignore_ascii_case(IO32BitDirectPixels) { - 32 - } else if pixel_encoding.eq_ignore_ascii_case(kIO30BitDirectPixels) { - 30 - } else if pixel_encoding.eq_ignore_ascii_case(IO16BitDirectPixels) { - 16 - } else if pixel_encoding.eq_ignore_ascii_case(IO8BitIndexedPixels) { - 8 - }else{ - 0 - } - } -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern "C" { - pub static CGRectNull: CGRect; - pub static CGRectInfinite: CGRect; - - pub static kCGDisplayShowDuplicateLowResolutionModes: CFStringRef; - - pub fn CGDisplayModeRelease(mode: ::sys::CGDisplayModeRef); - - pub fn CGMainDisplayID() -> CGDirectDisplayID; - pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID; - pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID; - pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double; - pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize; - pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t; - pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t; - pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t; - pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t; - pub fn CGGetActiveDisplayList( - max_displays: libc::uint32_t, - active_displays: *mut CGDirectDisplayID, - display_count: *mut libc::uint32_t, - ) -> CGError; - pub fn CGGetDisplaysWithRect( - rect: CGRect, - max_displays: libc::uint32_t, - displays: *mut CGDirectDisplayID, - matching_display_count: *mut libc::uint32_t, - ) -> CGError; - pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t; - pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t; - pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t; - pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect; - pub fn CGDisplayCreateImage(display: CGDirectDisplayID) -> ::sys::CGImageRef; - - pub fn CGBeginDisplayConfiguration(config: *const CGDisplayConfigRef) -> CGError; - pub fn CGCancelDisplayConfiguration(config: CGDisplayConfigRef) -> CGError; - pub fn CGCompleteDisplayConfiguration( - config: CGDisplayConfigRef, - option: CGConfigureOption, - ) -> CGError; - pub fn CGConfigureDisplayWithDisplayMode( - config: CGDisplayConfigRef, - display: CGDirectDisplayID, - mode: ::sys::CGDisplayModeRef, - options: CFDictionaryRef, - ) -> CGError; - - pub fn CGDisplayCopyDisplayMode(display: CGDirectDisplayID) -> ::sys::CGDisplayModeRef; - pub fn CGDisplayModeGetHeight(mode: ::sys::CGDisplayModeRef) -> libc::size_t; - pub fn CGDisplayModeGetWidth(mode: ::sys::CGDisplayModeRef) -> libc::size_t; - pub fn CGDisplayModeGetPixelHeight(mode: ::sys::CGDisplayModeRef) -> libc::size_t; - pub fn CGDisplayModeGetPixelWidth(mode: ::sys::CGDisplayModeRef) -> libc::size_t; - pub fn CGDisplayModeGetRefreshRate(mode: ::sys::CGDisplayModeRef) -> libc::c_double; - pub fn CGDisplayModeGetIOFlags(mode: ::sys::CGDisplayModeRef) -> libc::uint32_t; - pub fn CGDisplayModeCopyPixelEncoding(mode: ::sys::CGDisplayModeRef) -> CFStringRef; - - pub fn CGDisplayCopyAllDisplayModes( - display: CGDirectDisplayID, - options: CFDictionaryRef, - ) -> CFArrayRef; - - // mouse stuff - pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError; - pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError; - pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError; - pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError; - pub fn CGAssociateMouseAndMouseCursorPosition(connected: boolean_t) -> CGError; - - // Window Services Reference - pub fn CGWindowListCopyWindowInfo( - option: CGWindowListOption, - relativeToWindow: CGWindowID, - ) -> CFArrayRef; - pub fn CGWindowListCreateImage( - screenBounds: CGRect, - listOptions: CGWindowListOption, - windowId: CGWindowID, - imageOptions: CGWindowImageOption, - ) -> ::sys::CGImageRef; - pub fn CGWindowListCreateImageFromArray( - screenBounds: CGRect, - windowArray: CFArrayRef, - imageOptions: CGWindowImageOption, - ) -> ::sys::CGImageRef; -} diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/event.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/event.rs deleted file mode 100644 index 9d9ca18..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/event.rs +++ /dev/null @@ -1,669 +0,0 @@ -#![allow(non_upper_case_globals)] - -use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; -use geometry::CGPoint; -use event_source::CGEventSource; - -use libc; - -use foreign_types::ForeignType; - -pub type CGEventField = libc::uint32_t; -pub type CGKeyCode = libc::uint16_t; -pub type CGScrollEventUnit = libc::uint32_t; - -/// Flags for events -/// -/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) -bitflags! { - #[repr(C)] - pub struct CGEventFlags: u64 { - const CGEventFlagNull = 0; - - // Device-independent modifier key bits. - const CGEventFlagAlphaShift = 0x00010000; - const CGEventFlagShift = 0x00020000; - const CGEventFlagControl = 0x00040000; - const CGEventFlagAlternate = 0x00080000; - const CGEventFlagCommand = 0x00100000; - - // Special key identifiers. - const CGEventFlagHelp = 0x00400000; - const CGEventFlagSecondaryFn = 0x00800000; - - // Identifies key events from numeric keypad area on extended keyboards. - const CGEventFlagNumericPad = 0x00200000; - - // Indicates if mouse/pen movement events are not being coalesced - const CGEventFlagNonCoalesced = 0x00000100; - } -} - -/// Key codes for keys that are independent of keyboard layout. -/// -/// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h) -#[repr(C)] -pub struct KeyCode; -impl KeyCode { - pub const RETURN: CGKeyCode = 0x24; - pub const TAB: CGKeyCode = 0x30; - pub const SPACE: CGKeyCode = 0x31; - pub const DELETE: CGKeyCode = 0x33; - pub const ESCAPE: CGKeyCode = 0x35; - pub const COMMAND: CGKeyCode = 0x37; - pub const SHIFT: CGKeyCode = 0x38; - pub const CAPS_LOCK: CGKeyCode = 0x39; - pub const OPTION: CGKeyCode = 0x3A; - pub const CONTROL: CGKeyCode = 0x3B; - pub const RIGHT_COMMAND: CGKeyCode = 0x36; - pub const RIGHT_SHIFT: CGKeyCode = 0x3C; - pub const RIGHT_OPTION: CGKeyCode = 0x3D; - pub const RIGHT_CONTROL: CGKeyCode = 0x3E; - pub const FUNCTION: CGKeyCode = 0x3F; - pub const VOLUME_UP: CGKeyCode = 0x48; - pub const VOLUME_DOWN: CGKeyCode = 0x49; - pub const MUTE: CGKeyCode = 0x4A; - pub const F1: CGKeyCode = 0x7A; - pub const F2: CGKeyCode = 0x78; - pub const F3: CGKeyCode = 0x63; - pub const F4: CGKeyCode = 0x76; - pub const F5: CGKeyCode = 0x60; - pub const F6: CGKeyCode = 0x61; - pub const F7: CGKeyCode = 0x62; - pub const F8: CGKeyCode = 0x64; - pub const F9: CGKeyCode = 0x65; - pub const F10: CGKeyCode = 0x6D; - pub const F11: CGKeyCode = 0x67; - pub const F12: CGKeyCode = 0x6F; - pub const F13: CGKeyCode = 0x69; - pub const F14: CGKeyCode = 0x6B; - pub const F15: CGKeyCode = 0x71; - pub const F16: CGKeyCode = 0x6A; - pub const F17: CGKeyCode = 0x40; - pub const F18: CGKeyCode = 0x4F; - pub const F19: CGKeyCode = 0x50; - pub const F20: CGKeyCode = 0x5A; - pub const HELP: CGKeyCode = 0x72; - pub const HOME: CGKeyCode = 0x73; - pub const PAGE_UP: CGKeyCode = 0x74; - pub const FORWARD_DELETE: CGKeyCode = 0x75; - pub const END: CGKeyCode = 0x77; - pub const PAGE_DOWN: CGKeyCode = 0x79; - pub const LEFT_ARROW: CGKeyCode = 0x7B; - pub const RIGHT_ARROW: CGKeyCode = 0x7C; - pub const DOWN_ARROW: CGKeyCode = 0x7D; - pub const UP_ARROW: CGKeyCode = 0x7E; -} - -#[repr(C)] -pub struct ScrollEventUnit {} -impl ScrollEventUnit { - pub const PIXEL: CGScrollEventUnit = 0; - pub const LINE: CGScrollEventUnit = 1; -} - -/// Constants that specify the different types of input events. -/// -/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGEventType { - Null = 0, - - // Mouse events. - LeftMouseDown = 1, - LeftMouseUp = 2, - RightMouseDown = 3, - RightMouseUp = 4, - MouseMoved = 5, - LeftMouseDragged = 6, - RightMouseDragged = 7, - - // Keyboard events. - KeyDown = 10, - KeyUp = 11, - FlagsChanged = 12, - - // Specialized control devices. - ScrollWheel = 22, - TabletPointer = 23, - TabletProximity = 24, - OtherMouseDown = 25, - OtherMouseUp = 26, - OtherMouseDragged = 27, - - // Out of band event types. These are delivered to the event tap callback - // to notify it of unusual conditions that disable the event tap. - TapDisabledByTimeout = 0xFFFFFFFE, - TapDisabledByUserInput = 0xFFFFFFFF, -} - -/// Constants used as keys to access specialized fields in low-level events. -/// -/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield) -pub struct EventField; -impl EventField { - /// Key to access an integer field that contains the mouse button event - /// number. Matching mouse-down and mouse-up events will have the same - /// event number. - pub const MOUSE_EVENT_NUMBER: CGEventField = 0; - - /// Key to access an integer field that contains the mouse button click - /// state. A click state of 1 represents a single click. A click state of - /// 2 represents a double-click. A click state of 3 represents a - /// triple-click. - pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1; - - /// Key to access a double field that contains the mouse button pressure. - /// The pressure value may range from 0 to 1, with 0 representing the - /// mouse being up. This value is commonly set by tablet pens mimicking a - /// mouse. - pub const MOUSE_EVENT_PRESSURE: CGEventField = 2; - - /// Key to access an integer field that contains the mouse button number. - pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3; - - /// Key to access an integer field that contains the horizontal mouse - /// delta since the last mouse movement event. - pub const MOUSE_EVENT_DELTA_X: CGEventField = 4; - - /// Key to access an integer field that contains the vertical mouse delta - /// since the last mouse movement event. - pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5; - - /// Key to access an integer field. The value is non-zero if the event - /// should be ignored by the Inkwell subsystem. - pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6; - - /// Key to access an integer field that encodes the mouse event subtype as - /// a `kCFNumberIntType'. - pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7; - - /// Key to access an integer field, non-zero when this is an autorepeat of - /// a key-down, and zero otherwise. - pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8; - - /// Key to access an integer field that contains the virtual keycode of the - /// key-down or key-up event. - pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9; - - /// Key to access an integer field that contains the keyboard type - /// identifier. - pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10; - - /// Key to access an integer field that contains scrolling data. This field - /// typically contains the change in vertical position since the last - /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse - /// scroller. - pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11; - - /// Key to access an integer field that contains scrolling data. This field - /// typically contains the change in horizontal position since the last - /// scrolling event from a Mighty Mouse scroller. - pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12; - - /// Key to access a field that contains scrolling data. The scrolling data - /// represents a line-based or pixel-based change in vertical position - /// since the last scrolling event from a Mighty Mouse scroller or a - /// single-wheel mouse scroller. The scrolling data uses a fixed-point - /// 16.16 signed integer format. If this key is passed to - /// `CGEventGetDoubleValueField', the fixed-point value is converted to a - /// double value. - pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93; - - /// Key to access a field that contains scrolling data. The scrolling data - /// represents a line-based or pixel-based change in horizontal position - /// since the last scrolling event from a Mighty Mouse scroller. The - /// scrolling data uses a fixed-point 16.16 signed integer format. If this - /// key is passed to `CGEventGetDoubleValueField', the fixed-point value is - /// converted to a double value. - pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94; - - /// Key to access an integer field that contains pixel-based scrolling - /// data. The scrolling data represents the change in vertical position - /// since the last scrolling event from a Mighty Mouse scroller or a - /// single-wheel mouse scroller. - pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96; - - /// Key to access an integer field that contains pixel-based scrolling - /// data. The scrolling data represents the change in horizontal position - /// since the last scrolling event from a Mighty Mouse scroller. - pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97; - - /// Key to access an integer field that indicates whether the event should - /// be ignored by the Inkwell subsystem. If the value is non-zero, the - /// event should be ignored. - pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14; - - /// Key to access an integer field that contains the absolute X coordinate - /// in tablet space at full tablet resolution. - pub const TABLET_EVENT_POINT_X: CGEventField = 15; - - /// Key to access an integer field that contains the absolute Y coordinate - /// in tablet space at full tablet resolution. - pub const TABLET_EVENT_POINT_Y: CGEventField = 16; - - /// Key to access an integer field that contains the absolute Z coordinate - /// in tablet space at full tablet resolution. - pub const TABLET_EVENT_POINT_Z: CGEventField = 17; - - /// Key to access an integer field that contains the tablet button state. - /// Bit 0 is the first button, and a set bit represents a closed or pressed - /// button. Up to 16 buttons are supported. - pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18; - - /// Key to access a double field that contains the tablet pen pressure. A - /// value of 0.0 represents no pressure, and 1.0 represents maximum - /// pressure. - pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19; - - /// Key to access a double field that contains the horizontal tablet pen - /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. - pub const TABLET_EVENT_TILT_X: CGEventField = 20; - - /// Key to access a double field that contains the vertical tablet pen - /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. - pub const TABLET_EVENT_TILT_Y: CGEventField = 21; - - /// Key to access a double field that contains the tablet pen rotation. - pub const TABLET_EVENT_ROTATION: CGEventField = 22; - - /// Key to access a double field that contains the tangential pressure on - /// the device. A value of 0.0 represents no pressure, and 1.0 represents - /// maximum pressure. - pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23; - - /// Key to access an integer field that contains the system-assigned unique - /// device ID. - pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24; - - /// Key to access an integer field that contains a vendor-specified value. - pub const TABLET_EVENT_VENDOR_1: CGEventField = 25; - - /// Key to access an integer field that contains a vendor-specified value. - pub const TABLET_EVENT_VENDOR_2: CGEventField = 26; - - /// Key to access an integer field that contains a vendor-specified value. - pub const TABLET_EVENT_VENDOR_3: CGEventField = 27; - - /// Key to access an integer field that contains the vendor-defined ID, - /// typically the USB vendor ID. - pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28; - - /// Key to access an integer field that contains the vendor-defined tablet - /// ID, typically the USB product ID. - pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29; - - /// Key to access an integer field that contains the vendor-defined ID of - /// the pointing device. - pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30; - - /// Key to access an integer field that contains the system-assigned - /// device ID. - pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31; - - /// Key to access an integer field that contains the system-assigned - /// unique tablet ID. - pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32; - - /// Key to access an integer field that contains the vendor-assigned - /// pointer type. - pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33; - - /// Key to access an integer field that contains the vendor-defined - /// pointer serial number. - pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34; - - /// Key to access an integer field that contains the vendor-defined unique - /// ID. - pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35; - - /// Key to access an integer field that contains the device capabilities - /// mask. - pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36; - - /// Key to access an integer field that contains the pointer type. - pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37; - - /// Key to access an integer field that indicates whether the pen is in - /// proximity to the tablet. The value is non-zero if the pen is in - /// proximity to the tablet and zero when leaving the tablet. - pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38; - - /// Key to access a field that contains the event target process serial - /// number. The value is a 64-bit value. - pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39; - - /// Key to access a field that contains the event target Unix process ID. - pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40; - - /// Key to access a field that contains the event source Unix process ID. - pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41; - - /// Key to access a field that contains the event source user-supplied - /// data, up to 64 bits. - pub const EVENT_SOURCE_USER_DATA: CGEventField = 42; - - /// Key to access a field that contains the event source Unix effective UID. - pub const EVENT_SOURCE_USER_ID: CGEventField = 43; - - /// Key to access a field that contains the event source Unix effective - /// GID. - pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44; - - /// Key to access a field that contains the event source state ID used to - /// create this event. - pub const EVENT_SOURCE_STATE_ID: CGEventField = 45; - - /// Key to access an integer field that indicates whether a scrolling event - /// contains continuous, pixel-based scrolling data. The value is non-zero - /// when the scrolling data is pixel-based and zero when the scrolling data - /// is line-based. - pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88; - - /// Added in 10.5; made public in 10.7. - pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91; - pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92; -} - -// Constants that specify buttons on a one, two, or three-button mouse. -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGMouseButton { - Left, - Right, - Center, -} - -/// Possible tapping points for events. -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGEventTapLocation { - HID, - Session, - AnnotatedSession, -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGEvent; - fn drop = |p| CFRelease(p as *mut _); - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGEvent; - pub struct CGEventRef; -} - -impl CGEvent { - pub fn type_id() -> CFTypeID { - unsafe { - CGEventGetTypeID() - } - } - - pub fn new(source: CGEventSource) -> Result { - unsafe { - let event_ref = CGEventCreate(source.as_ptr()); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - pub fn new_keyboard_event( - source: CGEventSource, - keycode: CGKeyCode, - keydown: bool - ) -> Result { - unsafe { - let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - pub fn new_mouse_event( - source: CGEventSource, - mouse_type: CGEventType, - mouse_cursor_position: CGPoint, - mouse_button: CGMouseButton - ) -> Result { - unsafe { - let event_ref = CGEventCreateMouseEvent(source.as_ptr(), mouse_type, - mouse_cursor_position, mouse_button); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - #[cfg(feature = "highsierra")] - pub fn new_scroll_event( - source: CGEventSource, - units: CGScrollEventUnit, - wheel_count: u32, - wheel1: i32, - wheel2: i32, - wheel3: i32, - ) -> Result { - unsafe { - let event_ref = CGEventCreateScrollWheelEvent2( - source.as_ptr(), - units, - wheel_count, - wheel1, - wheel2, - wheel3, - ); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - pub fn post(&self, tap_location: CGEventTapLocation) { - unsafe { - CGEventPost(tap_location, self.as_ptr()); - } - } - - pub fn location(&self) -> CGPoint { - unsafe { - CGEventGetLocation(self.as_ptr()) - } - } - - #[cfg(feature = "elcapitan")] - pub fn post_to_pid(&self, pid: libc::pid_t) { - unsafe { - CGEventPostToPid(pid, self.as_ptr()); - } - } - - pub fn set_flags(&self, flags: CGEventFlags) { - unsafe { - CGEventSetFlags(self.as_ptr(), flags); - } - } - - pub fn get_flags(&self) -> CGEventFlags { - unsafe { - CGEventGetFlags(self.as_ptr()) - } - } - - pub fn set_type(&self, event_type: CGEventType) { - unsafe { - CGEventSetType(self.as_ptr(), event_type); - } - } - - pub fn get_type(&self) -> CGEventType { - unsafe { - CGEventGetType(self.as_ptr()) - } - } - - pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) { - let buflen = buf.len() as libc::c_ulong; - unsafe { - CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr()); - } - } - - pub fn set_string(&self, string: &str) { - let buf: Vec = string.encode_utf16().collect(); - self.set_string_from_utf16_unchecked(&buf); - } - - pub fn get_integer_value_field(&self, field: CGEventField) -> i64 { - unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) } - } - - pub fn set_integer_value_field(&self, field: CGEventField, value: i64) { - unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) } - } - - pub fn get_double_value_field(&self, field: CGEventField) -> f64 { - unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) } - } - - pub fn set_double_value_field(&self, field: CGEventField, value: f64) { - unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) } - } -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - /// Return the type identifier for the opaque type `CGEventRef'. - fn CGEventGetTypeID() -> CFTypeID; - - /// Return a new event using the event source `source'. If `source' is NULL, - /// the default source is used. - fn CGEventCreate(source: ::sys::CGEventSourceRef) -> ::sys::CGEventRef; - - /// Return a new keyboard event. - /// - /// The event source may be taken from another event, or may be NULL. Based - /// on the virtual key code values entered, the appropriate key down, key up, - /// or flags changed events are generated. - /// - /// All keystrokes needed to generate a character must be entered, including - /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z', - /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT - /// and 'z' key must be released: - fn CGEventCreateKeyboardEvent(source: ::sys::CGEventSourceRef, keycode: CGKeyCode, - keydown: bool) -> ::sys::CGEventRef; - - /// Return a new mouse event. - /// - /// The event source may be taken from another event, or may be NULL. - /// `mouseType' should be one of the mouse event types. `mouseCursorPosition' - /// should be the position of the mouse cursor in global coordinates. - /// `mouseButton' should be the button that's changing state; `mouseButton' - /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown', - /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'. - /// - /// The current implementation of the event system supports a maximum of - /// thirty-two buttons. Mouse button 0 is the primary button on the mouse. - /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is - /// the center button, and the remaining buttons are in USB device order. - fn CGEventCreateMouseEvent(source: ::sys::CGEventSourceRef, mouseType: CGEventType, - mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> ::sys::CGEventRef; - - /// A non-variadic variant version of CGEventCreateScrollWheelEvent. - /// - /// Returns a new Quartz scrolling event. - /// - /// This function allows you to create a scrolling event and customize the - /// event before posting it to the event system. - #[cfg(feature = "highsierra")] - fn CGEventCreateScrollWheelEvent2( - source: ::sys::CGEventSourceRef, - units: CGScrollEventUnit, - wheelCount: libc::uint32_t, - wheel1: libc::int32_t, - wheel2: libc::int32_t, - wheel3: libc::int32_t, - ) -> ::sys::CGEventRef; - - /// Post an event into the event stream at a specified location. - /// - /// This function posts the specified event immediately before any event taps - /// instantiated for that location, and the event passes through any such - /// taps. - fn CGEventPost(tapLocation: CGEventTapLocation, event: ::sys::CGEventRef); - - #[cfg(feature = "elcapitan")] - /// Post an event to a specified process ID - fn CGEventPostToPid(pid: libc::pid_t, event: ::sys::CGEventRef); - - /// Set the event flags of an event. - fn CGEventSetFlags(event: ::sys::CGEventRef, flags: CGEventFlags); - - /// Return the event flags of an event. - fn CGEventGetFlags(event: ::sys::CGEventRef) -> CGEventFlags; - - /// Return the location of an event in global display coordinates. - /// CGPointZero is returned if event is not a valid ::sys::CGEventRef. - fn CGEventGetLocation(event: ::sys::CGEventRef) -> CGPoint; - - /// Set the event type of an event. - fn CGEventSetType(event: ::sys::CGEventRef, eventType: CGEventType); - - /// Return the event type of an event (left mouse down, for example). - fn CGEventGetType(event: ::sys::CGEventRef) -> CGEventType; - - /// Set the Unicode string associated with a keyboard event. - /// - /// By default, the system translates the virtual key code in a keyboard - /// event into a Unicode string based on the keyboard ID in the event - /// source. This function allows you to manually override this string. - /// Note that application frameworks may ignore the Unicode string in a - /// keyboard event and do their own translation based on the virtual - /// keycode and perceived event state. - fn CGEventKeyboardSetUnicodeString(event: ::sys::CGEventRef, - length: libc::c_ulong, - string: *const u16); - - /// Return the integer value of a field in an event. - fn CGEventGetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField) -> i64; - - /// Set the integer value of a field in an event. - /// - /// Before calling this function, the event type must be set using a typed - /// event creation function such as `CGEventCreateMouseEvent', or by - /// calling `CGEventSetType'. - /// - /// If you are creating a mouse event generated by a tablet, call this - /// function and specify the field `kCGMouseEventSubtype' with a value of - /// `kCGEventMouseSubtypeTabletPoint' or - /// `kCGEventMouseSubtypeTabletProximity' before setting other parameters. - fn CGEventSetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField, value: i64); - - /// Return the floating-point value of a field in an event. - /// - /// In cases where the field value is represented within the event by a fixed - /// point number or an integer, the result is scaled to the appropriate range - /// as part of creating the floating-point representation. - fn CGEventGetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField) -> f64; - - /// Set the floating-point value of a field in an event. - /// - /// Before calling this function, the event type must be set using a typed - /// event creation function such as `CGEventCreateMouseEvent', or by calling - /// `CGEventSetType'. - /// - /// In cases where the field’s value is represented within the event by a - /// fixed point number or integer, the value parameter is scaled as needed - /// and converted to the appropriate type. - fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64); -} diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/font.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/font.rs deleted file mode 100644 index fc7a9ba..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/font.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ptr; -use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType}; -use core_foundation::array::{CFArray, CFArrayRef}; -use core_foundation::data::{CFData, CFDataRef}; -use core_foundation::number::CFNumber; -use core_foundation::string::{CFString, CFStringRef}; -use core_foundation::dictionary::{CFDictionary, CFDictionaryRef}; -use data_provider::CGDataProvider; -use geometry::CGRect; - -use foreign_types::ForeignType; - -use libc::{self, c_int, size_t}; - -pub type CGGlyph = libc::c_ushort; - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGFont; - fn drop = |p| CFRelease(p as *mut _); - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGFont; - pub struct CGFontRef; -} - -unsafe impl Send for CGFont {} -unsafe impl Sync for CGFont {} - -impl CGFont { - pub fn type_id() -> CFTypeID { - unsafe { - CGFontGetTypeID() - } - } - - pub fn from_data_provider(provider: CGDataProvider) -> Result { - unsafe { - let font_ref = CGFontCreateWithDataProvider(provider.as_ptr()); - if !font_ref.is_null() { - Ok(CGFont::from_ptr(font_ref)) - } else { - Err(()) - } - } - } - - pub fn from_name(name: &CFString) -> Result { - unsafe { - let font_ref = CGFontCreateWithFontName(name.as_concrete_TypeRef()); - if !font_ref.is_null() { - Ok(CGFont::from_ptr(font_ref)) - } else { - Err(()) - } - } - } - - pub fn create_copy_from_variations(&self, vars: &CFDictionary) -> Result { - unsafe { - let font_ref = CGFontCreateCopyWithVariations(self.as_ptr(), - vars.as_concrete_TypeRef()); - if !font_ref.is_null() { - Ok(CGFont::from_ptr(font_ref)) - } else { - Err(()) - } - } - } - - pub fn postscript_name(&self) -> CFString { - unsafe { - let string_ref = CGFontCopyPostScriptName(self.as_ptr()); - TCFType::wrap_under_create_rule(string_ref) - } - } - - pub fn get_glyph_b_boxes(&self, glyphs: &[CGGlyph], bboxes: &mut [CGRect]) -> bool { - unsafe { - assert!(bboxes.len() >= glyphs.len()); - CGFontGetGlyphBBoxes(self.as_ptr(), - glyphs.as_ptr(), - glyphs.len(), - bboxes.as_mut_ptr()) - } - } - - pub fn get_glyph_advances(&self, glyphs: &[CGGlyph], advances: &mut [c_int]) -> bool { - unsafe { - assert!(advances.len() >= glyphs.len()); - CGFontGetGlyphAdvances(self.as_ptr(), - glyphs.as_ptr(), - glyphs.len(), - advances.as_mut_ptr()) - } - } - - pub fn get_units_per_em(&self) -> c_int { - unsafe { - CGFontGetUnitsPerEm(self.as_ptr()) - } - } - - pub fn copy_table_tags(&self) -> CFArray { - unsafe { - TCFType::wrap_under_create_rule(CGFontCopyTableTags(self.as_ptr())) - } - } - - pub fn copy_table_for_tag(&self, tag: u32) -> Option { - let data_ref = unsafe { CGFontCopyTableForTag(self.as_ptr(), tag) }; - if data_ref != ptr::null() { - Some(unsafe { TCFType::wrap_under_create_rule(data_ref) }) - } else { - None - } - } -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - // TODO: basically nothing has bindings (even commented-out) besides what we use. - fn CGFontCreateWithDataProvider(provider: ::sys::CGDataProviderRef) -> ::sys::CGFontRef; - fn CGFontCreateWithFontName(name: CFStringRef) -> ::sys::CGFontRef; - fn CGFontCreateCopyWithVariations(font: ::sys::CGFontRef, vars: CFDictionaryRef) -> ::sys::CGFontRef; - fn CGFontGetTypeID() -> CFTypeID; - - fn CGFontCopyPostScriptName(font: ::sys::CGFontRef) -> CFStringRef; - - // These do the same thing as CFRetain/CFRelease, except - // gracefully handle a NULL argument. We don't use them. - //fn CGFontRetain(font: ::sys::CGFontRef); - //fn CGFontRelease(font: ::sys::CGFontRef); - - fn CGFontGetGlyphBBoxes(font: ::sys::CGFontRef, - glyphs: *const CGGlyph, - count: size_t, - bboxes: *mut CGRect) - -> bool; - fn CGFontGetGlyphAdvances(font: ::sys::CGFontRef, - glyphs: *const CGGlyph, - count: size_t, - advances: *mut c_int) - -> bool; - fn CGFontGetUnitsPerEm(font: ::sys::CGFontRef) -> c_int; - - fn CGFontCopyTableTags(font: ::sys::CGFontRef) -> CFArrayRef; - fn CGFontCopyTableForTag(font: ::sys::CGFontRef, tag: u32) -> CFDataRef; -} diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/geometry.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/geometry.rs deleted file mode 100644 index b22c704..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/geometry.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use base::CGFloat; -use core_foundation::base::TCFType; -use core_foundation::dictionary::CFDictionary; - -pub const CG_ZERO_POINT: CGPoint = CGPoint { - x: 0.0, - y: 0.0, -}; - -pub const CG_ZERO_SIZE: CGSize = CGSize { - width: 0.0, - height: 0.0, -}; - -pub const CG_ZERO_RECT: CGRect = CGRect { - origin: CG_ZERO_POINT, - size: CG_ZERO_SIZE, -}; - -pub const CG_AFFINE_TRANSFORM_IDENTITY: CGAffineTransform = CGAffineTransform { - a: 1.0, b: 0.0, - c: 0.0, d: 1.0, - tx: 0.0, ty: 0.0, -}; - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CGSize { - pub width: CGFloat, - pub height: CGFloat, -} - -impl CGSize { - #[inline] - pub fn new(width: CGFloat, height: CGFloat) -> CGSize { - CGSize { - width: width, - height: height, - } - } - - #[inline] - pub fn apply_transform(&self, t: &CGAffineTransform) -> CGSize { - unsafe { - ffi::CGSizeApplyAffineTransform(*self, *t) - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CGPoint { - pub x: CGFloat, - pub y: CGFloat, -} - -impl CGPoint { - #[inline] - pub fn new(x: CGFloat, y: CGFloat) -> CGPoint { - CGPoint { - x: x, - y: y, - } - } - - #[inline] - pub fn apply_transform(&self, t: &CGAffineTransform) -> CGPoint { - unsafe { - ffi::CGPointApplyAffineTransform(*self, *t) - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CGRect { - pub origin: CGPoint, - pub size: CGSize -} - -impl CGRect { - #[inline] - pub fn new(origin: &CGPoint, size: &CGSize) -> CGRect { - CGRect { - origin: *origin, - size: *size, - } - } - - #[inline] - pub fn inset(&self, size: &CGSize) -> CGRect { - unsafe { - ffi::CGRectInset(*self, size.width, size.height) - } - } - - #[inline] - pub fn from_dict_representation(dict: &CFDictionary) -> Option { - let mut rect = CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(0., 0.)); - let result = unsafe { - ffi::CGRectMakeWithDictionaryRepresentation(dict.as_concrete_TypeRef(), &mut rect) - }; - if result == 0 { - None - } else { - Some(rect) - } - } - - #[inline] - pub fn is_empty(&self) -> bool { - unsafe { - // I use one, as it seems that `YES` is not available from this crate. - ffi::CGRectIsEmpty(*self) == 1 - } - } - - #[inline] - pub fn is_intersects(&self, other: &CGRect) -> bool { - unsafe { - // I use one, as it seems that `YES` is not available from this crate. - ffi::CGRectIntersectsRect(*self, *other) == 1 - } - } - - #[inline] - pub fn apply_transform(&self, t: &CGAffineTransform) -> CGRect { - unsafe { - ffi::CGRectApplyAffineTransform(*self, *t) - } - } -} - -impl PartialEq for CGRect { - #[inline] - fn eq(&self, other: &CGRect) -> bool { - unsafe { - ffi::CGRectEqualToRect(*self, *other) != 0 - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CGAffineTransform { - pub a: CGFloat, - pub b: CGFloat, - pub c: CGFloat, - pub d: CGFloat, - pub tx: CGFloat, - pub ty: CGFloat, -} - -impl CGAffineTransform { - #[inline] - pub fn new( - a: CGFloat, - b: CGFloat, - c: CGFloat, - d: CGFloat, - tx: CGFloat, - ty: CGFloat, - ) -> CGAffineTransform { - CGAffineTransform { a, b, c, d, tx, ty } - } - - #[inline] - pub fn invert(&self) -> CGAffineTransform { - unsafe { - ffi::CGAffineTransformInvert(*self) - } - } -} - -mod ffi { - use base::{CGFloat, boolean_t}; - use geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; - use core_foundation::dictionary::CFDictionaryRef; - - #[link(name = "CoreGraphics", kind = "framework")] - extern { - pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect; - pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef, - rect: *mut CGRect) -> boolean_t; - pub fn CGRectIsEmpty(rect: CGRect) -> boolean_t; - pub fn CGRectIntersectsRect(rect1: CGRect, rect2: CGRect) -> boolean_t; - pub fn CGRectEqualToRect(rect1: CGRect, rect2: CGRect) -> boolean_t; - - pub fn CGAffineTransformInvert(t: CGAffineTransform) -> CGAffineTransform; - - pub fn CGPointApplyAffineTransform(point: CGPoint, t: CGAffineTransform) -> CGPoint; - pub fn CGRectApplyAffineTransform(rect: CGRect, t: CGAffineTransform) -> CGRect; - pub fn CGSizeApplyAffineTransform(size: CGSize, t: CGAffineTransform) -> CGSize; - } -} - diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/image.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/image.rs deleted file mode 100644 index 84945e8..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/image.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::ptr; - -use base::CGFloat; -use core_foundation::base::{CFRetain, CFTypeID}; -use core_foundation::data::CFData; -use color_space::CGColorSpace; -use data_provider::{CGDataProviderRef, CGDataProvider}; -use geometry::CGRect; -use libc::size_t; -use foreign_types::{ForeignType, ForeignTypeRef}; - -#[repr(C)] -pub enum CGImageAlphaInfo { - CGImageAlphaNone, /* For example, RGB. */ - CGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ - CGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ - CGImageAlphaLast, /* For example, non-premultiplied RGBA */ - CGImageAlphaFirst, /* For example, non-premultiplied ARGB */ - CGImageAlphaNoneSkipLast, /* For example, RBGX. */ - CGImageAlphaNoneSkipFirst, /* For example, XRBG. */ - CGImageAlphaOnly /* No color data, alpha data only */ -} - -#[repr(C)] -pub enum CGImageByteOrderInfo { - CGImageByteOrderMask = 0x7000, - CGImageByteOrder16Little = (1 << 12), - CGImageByteOrder32Little = (2 << 12), - CGImageByteOrder16Big = (3 << 12), - CGImageByteOrder32Big = (4 << 12) -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGImage; - fn drop = CGImageRelease; - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGImage; - pub struct CGImageRef; -} - -impl CGImage { - pub fn new(width: size_t, - height: size_t, - bits_per_component: size_t, - bits_per_pixel: size_t, - bytes_per_row: size_t, - colorspace: &CGColorSpace, - bitmap_info: u32, - provider: &CGDataProvider, - should_interpolate: bool, - rendering_intent: u32) - -> Self { - unsafe { - let result = CGImageCreate(width, - height, - bits_per_component, - bits_per_pixel, - bytes_per_row, - colorspace.as_ptr(), - bitmap_info, - provider.as_ptr(), - ptr::null_mut(), - should_interpolate, - rendering_intent); - assert!(!result.is_null()); - Self::from_ptr(result) - } - } - - pub fn type_id() -> CFTypeID { - unsafe { - CGImageGetTypeID() - } - } -} - -impl CGImageRef { - pub fn width(&self) -> size_t { - unsafe { - CGImageGetWidth(self.as_ptr()) - } - } - - pub fn height(&self) -> size_t { - unsafe { - CGImageGetHeight(self.as_ptr()) - } - } - - pub fn bits_per_component(&self) -> size_t { - unsafe { - CGImageGetBitsPerComponent(self.as_ptr()) - } - } - - pub fn bits_per_pixel(&self) -> size_t { - unsafe { - CGImageGetBitsPerPixel(self.as_ptr()) - } - } - - pub fn bytes_per_row(&self) -> size_t { - unsafe { - CGImageGetBytesPerRow(self.as_ptr()) - } - } - - pub fn color_space(&self) -> CGColorSpace { - unsafe { - let cs = CGImageGetColorSpace(self.as_ptr()); - CFRetain(cs as *mut _); - CGColorSpace::from_ptr(cs) - } - } - - /// Returns the raw image bytes wrapped in `CFData`. Note, the returned `CFData` owns the - /// underlying buffer. - pub fn data(&self) -> CFData { - let data_provider = unsafe { - CGDataProviderRef::from_ptr(CGImageGetDataProvider(self.as_ptr())) - }; - data_provider.copy_data() - } - - /// Returns a cropped image. If the `rect` specifies a rectangle which lies outside of the - /// image bounds, the `None` is returned. - pub fn cropped(&self, rect: CGRect) -> Option { - let image_ptr = unsafe { CGImageCreateWithImageInRect(self.as_ptr(), rect) }; - if !image_ptr.is_null() { - Some(unsafe { CGImage::from_ptr(image_ptr) }) - } else { - None - } - } -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - fn CGImageGetTypeID() -> CFTypeID; - fn CGImageGetWidth(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetHeight(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetBitsPerComponent(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetBitsPerPixel(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetBytesPerRow(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetColorSpace(image: ::sys::CGImageRef) -> ::sys::CGColorSpaceRef; - fn CGImageGetDataProvider(image: ::sys::CGImageRef) -> ::sys::CGDataProviderRef; - fn CGImageRelease(image: ::sys::CGImageRef); - fn CGImageCreate(width: size_t, - height: size_t, - bitsPerComponent: size_t, - bitsPerPixel: size_t, - bytesPerRow: size_t, - space: ::sys::CGColorSpaceRef, - bitmapInfo: u32, - provider: ::sys::CGDataProviderRef, - decode: *const CGFloat, - shouldInterpolate: bool, - intent: u32) - -> ::sys::CGImageRef; - fn CGImageCreateWithImageInRect(image: ::sys::CGImageRef, rect: CGRect) -> ::sys::CGImageRef; - - //fn CGImageGetAlphaInfo(image: ::sys::CGImageRef) -> CGImageAlphaInfo; - //fn CGImageCreateCopyWithColorSpace(image: ::sys::CGImageRef, space: ::sys::CGColorSpaceRef) -> ::sys::CGImageRef -} diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/lib.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/lib.rs deleted file mode 100644 index 981883c..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate libc; - -#[macro_use] -extern crate core_foundation; - -#[macro_use] -#[cfg(target_os = "macos")] -extern crate bitflags; - -#[macro_use] -extern crate foreign_types; - -pub mod base; -pub mod color; -pub mod color_space; -pub mod context; -pub mod data_provider; -#[cfg(target_os = "macos")] -pub mod display; -#[cfg(target_os = "macos")] -pub mod event; -#[cfg(target_os = "macos")] -pub mod event_source; -pub mod font; -pub mod geometry; -#[cfg(target_os = "macos")] -pub mod window; -#[cfg(target_os = "macos")] -pub mod private; -pub mod image; -pub mod path; -mod sys; diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/sys.rs b/third_party/cargo/vendor/core-graphics-0.17.3/src/sys.rs deleted file mode 100644 index ccf0625..0000000 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/sys.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::os::raw::c_void; - -pub enum CGImage {} -pub type CGImageRef = *mut CGImage; - -#[repr(C)] -pub struct __CGColor(c_void); - -pub type CGColorRef = *const __CGColor; - -pub enum CGColorSpace {} -pub type CGColorSpaceRef = *mut CGColorSpace; - -pub enum CGPath {} -pub type CGPathRef = *mut CGPath; - -pub enum CGDataProvider {} -pub type CGDataProviderRef = *mut CGDataProvider; - -pub enum CGFont {} -pub type CGFontRef = *mut CGFont; - -pub enum CGContext {} -pub type CGContextRef = *mut CGContext; - -#[cfg(target_os = "macos")] -mod macos { - pub enum CGEvent {} - pub type CGEventRef = *mut CGEvent; - - pub enum CGEventSource {} - pub type CGEventSourceRef = *mut CGEventSource; - - pub enum CGDisplayMode {} - pub type CGDisplayModeRef = *mut CGDisplayMode; -} - -#[cfg(target_os = "macos")] -pub use self::macos::*; diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/.cargo-checksum.json b/third_party/cargo/vendor/core-graphics-0.19.0/.cargo-checksum.json deleted file mode 100644 index deede98..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"fccf58052cf6a36aba8ce4936d5e62d953f73a1fbedbe89b6d099bcd3848a5a5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"6745c3c38183d2eda9b1fa265fb0a95018db5c110cbabc00b32327d951bbe2ea","src/base.rs":"89e01071e66f0c66fa22d94fd666100c89f6a20d988fb8bacbf86b8ed633bcbd","src/color.rs":"4c8ec4ab828cbc1b2a1538a34a51f5b380927f2f1daf187dff6f732f57a43656","src/color_space.rs":"b3d7ee8a21703c789160867cb8eb2188bd1daa193e3d030f21adb6f1a6f872de","src/context.rs":"b4b05d7c75337e8f8ece3143d1f1a48b3ae6868c473469c2ce7fd030512f9aff","src/data_provider.rs":"9e8a17075b1527f87111fd4102252e086bf9fde147483f21a661773e133f7c71","src/display.rs":"cc691712c3d27342ae97f04df6032d6f682570239ba51936fcc796c61bf08c8b","src/event.rs":"593d7f6c0621f8803546562548f98985f171eb74b513d6f9b9081fe6f2d1a1a8","src/event_source.rs":"d55a4f5b5e62789325028febc51bbf54c74b15ab1a4e70c6ad749a2f9753e081","src/font.rs":"e1d2be7f909fd5876f3cd1649d54ef0a9d7dcd4151c027a25049be7084ca8a9f","src/geometry.rs":"49d27dde6672e5654f796ec3399216ab6d1cf9ed9d3506a824c8e9eec6e3db00","src/image.rs":"0af720ee020fb1c6a2f4b1ce49e3d27f8f21f0be6b81ba4b9c824f87564efa58","src/lib.rs":"9b9601462de1bbc806e881b2b42e86b16372cad8eeefe1a96b772a9f7329958d","src/path.rs":"c429afeaed999b02ac00f89a867b5fc64f1e223039079a4e0529306b734ff117","src/private.rs":"da3fd61338bab2d8e26aa5433b2e18ecd2a0a408c62e1ac2b33a0f87f2dad88a","src/sys.rs":"cc90b690f172da51a87ffb234f6e74a9f501c4f1630d7b51fa2d5846e80fc164","src/window.rs":"2f6c3dc958ae2c0c9e2fc5033300b96e60ed0abee9823ea1f03797d64df0911a"},"package":"59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/BUILD.bazel b/third_party/cargo/vendor/core-graphics-0.19.0/BUILD.bazel deleted file mode 100644 index cb3cfa7..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/BUILD.bazel +++ /dev/null @@ -1,58 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "core_graphics", - srcs = glob(["**/*.rs"]), - crate_features = [ - "default", - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.19.0", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", - "//third_party/cargo/vendor/core-foundation-0.7.0:core_foundation", - "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", - "//third_party/cargo/vendor/libc-0.2.71:libc", - ], -) diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/Cargo.toml b/third_party/cargo/vendor/core-graphics-0.19.0/Cargo.toml deleted file mode 100644 index ccffdb8..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "core-graphics" -version = "0.19.0" -authors = ["The Servo Project Developers"] -description = "Bindings to Core Graphics for macOS" -homepage = "https://github.com/servo/core-graphics-rs" -license = "MIT / Apache-2.0" -repository = "https://github.com/servo/core-foundation-rs" -[dependencies.bitflags] -version = "1.0" - -[dependencies.core-foundation] -version = "0.7" - -[dependencies.foreign-types] -version = "0.3.0" - -[dependencies.libc] -version = "0.2" - -[features] -default = [] -elcapitan = [] -highsierra = [] diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/base.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/base.rs deleted file mode 100644 index 89ca6b0..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/base.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// this file defines CGFloat, as well as stubbed data types. - -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] - -use libc; - -#[cfg(any(target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64"))] -pub type boolean_t = libc::c_int; -#[cfg(target_arch = "x86_64")] -pub type boolean_t = libc::c_uint; - -#[cfg(target_pointer_width = "64")] -pub type CGFloat = libc::c_double; -#[cfg(not(target_pointer_width = "64"))] -pub type CGFloat = libc::c_float; - -pub type CGError = i32; - -pub const kCGImageAlphaNone: u32 = 0; -pub const kCGImageAlphaPremultipliedLast: u32 = 1; -pub const kCGImageAlphaPremultipliedFirst: u32 = 2; -pub const kCGImageAlphaLast: u32 = 3; -pub const kCGImageAlphaFirst: u32 = 4; -pub const kCGImageAlphaNoneSkipLast: u32 = 5; -pub const kCGImageAlphaNoneSkipFirst: u32 = 6; - -pub const kCGBitmapByteOrderDefault: u32 = (0 << 12); -pub const kCGBitmapByteOrder16Little: u32 = (1 << 12); -pub const kCGBitmapByteOrder32Little: u32 = (2 << 12); -pub const kCGBitmapByteOrder16Big: u32 = (3 << 12); -pub const kCGBitmapByteOrder32Big: u32 = (4 << 12); - -pub const kCGRenderingIntentDefault: u32 = 0; -pub const kCGRenderingIntentAbsoluteColorimetric: u32 = 1; -pub const kCGRenderingIntentRelativeColorimetric: u32 = 2; -pub const kCGRenderingIntentPerceptual: u32 = 3; -pub const kCGRenderingIntentSaturation: u32 = 4; - -#[cfg(target_endian = "big")] -pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Big; -#[cfg(target_endian = "big")] -pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Big; - -#[cfg(target_endian = "little")] -pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Little; -#[cfg(target_endian = "little")] -pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Little; diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/context.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/context.rs deleted file mode 100644 index ec0b7b1..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/context.rs +++ /dev/null @@ -1,685 +0,0 @@ -// Copyright 2015 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use base::CGFloat; -use color_space::CGColorSpace; -use core_foundation::base::{ToVoid, CFRelease, CFRetain, CFTypeID}; -use font::{CGFont, CGGlyph}; -use geometry::CGPoint; -use color::CGColor; -use path::CGPathRef; -use libc::{c_int, size_t}; -use std::os::raw::c_void; - -use std::cmp; -use std::ptr; -use std::slice; -use geometry::{CGAffineTransform, CGRect}; -use image::CGImage; -use foreign_types::{ForeignType, ForeignTypeRef}; - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGBlendMode { - Normal = 0, - Multiply, - Screen, - Overlay, - Darken, - Lighten, - ColorDodge, - ColorBurn, - SoftLight, - HardLight, - Difference, - Exclusion, - Hue, - Saturation, - Color, - Luminosity, - // 10.5 and up: - Clear, - Copy, - SourceIn, - SourceOut, - SourceAtop, - DestinationOver, - DestinationIn, - DestinationOut, - DestinationAtop, - Xor, - PlusDarker, - PlusLighter, -} - -#[repr(C)] -pub enum CGTextDrawingMode { - CGTextFill, - CGTextStroke, - CGTextFillStroke, - CGTextInvisible, - CGTextFillClip, - CGTextStrokeClip, - CGTextClip -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGLineCap { - CGLineCapButt, - CGLineCapRound, - CGLineCapSquare, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGLineJoin { - CGLineJoinMiter, - CGLineJoinRound, - CGLineJoinBevel, -} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGPathDrawingMode { - CGPathFill, - CGPathEOFill, - CGPathStroke, - CGPathFillStroke, - CGPathEOFillStroke, -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGContext; - fn drop = |cs| CFRelease(cs as *mut _); - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGContext; - pub struct CGContextRef; -} - -impl CGContext { - pub fn type_id() -> CFTypeID { - unsafe { - CGContextGetTypeID() - } - } - - pub fn create_bitmap_context(data: Option<*mut c_void>, - width: size_t, - height: size_t, - bits_per_component: size_t, - bytes_per_row: size_t, - space: &CGColorSpace, - bitmap_info: u32) - -> CGContext { - unsafe { - let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()), - width, - height, - bits_per_component, - bytes_per_row, - space.as_ptr(), - bitmap_info); - assert!(!result.is_null()); - Self::from_ptr(result) - } - } - - pub fn data(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut( - CGBitmapContextGetData(self.as_ptr()) as *mut u8, - (self.height() * self.bytes_per_row()) as usize) - } - } -} - -impl CGContextRef { - pub fn flush(&self) { - unsafe { - CGContextFlush(self.as_ptr()) - } - } - - pub fn width(&self) -> size_t { - unsafe { - CGBitmapContextGetWidth(self.as_ptr()) - } - } - - pub fn height(&self) -> size_t { - unsafe { - CGBitmapContextGetHeight(self.as_ptr()) - } - } - - pub fn bytes_per_row(&self) -> size_t { - unsafe { - CGBitmapContextGetBytesPerRow(self.as_ptr()) - } - } - - pub fn clip_bounding_box(&self) -> CGRect { - unsafe { - CGContextGetClipBoundingBox(self.as_ptr()) - } - } - - pub fn set_fill_color(&self, color: &CGColor) { - unsafe { - CGContextSetFillColorWithColor(self.as_ptr(), color.to_void()); - } - } - - pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { - unsafe { - CGContextSetRGBFillColor(self.as_ptr(), red, green, blue, alpha) - } - } - - pub fn set_rgb_stroke_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { - unsafe { - CGContextSetRGBStrokeColor(self.as_ptr(), red, green, blue, alpha) - } - } - - pub fn set_gray_fill_color(&self, gray: CGFloat, alpha: CGFloat) { - unsafe { - CGContextSetGrayFillColor(self.as_ptr(), gray, alpha) - } - } - - pub fn set_blend_mode(&self, blend_mode: CGBlendMode) { - unsafe { - CGContextSetBlendMode(self.as_ptr(), blend_mode) - } - } - - pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) { - unsafe { - CGContextSetAllowsFontSmoothing(self.as_ptr(), allows_font_smoothing) - } - } - - pub fn set_font_smoothing_style(&self, style: i32) { - unsafe { - CGContextSetFontSmoothingStyle(self.as_ptr(), style as _); - } - } - - pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) { - unsafe { - CGContextSetShouldSmoothFonts(self.as_ptr(), should_smooth_fonts) - } - } - - pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) { - unsafe { - CGContextSetAllowsAntialiasing(self.as_ptr(), allows_antialiasing) - } - } - - pub fn set_should_antialias(&self, should_antialias: bool) { - unsafe { - CGContextSetShouldAntialias(self.as_ptr(), should_antialias) - } - } - - pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) { - unsafe { - CGContextSetAllowsFontSubpixelQuantization(self.as_ptr(), allows_font_subpixel_quantization) - } - } - - pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) { - unsafe { - CGContextSetShouldSubpixelQuantizeFonts(self.as_ptr(), should_subpixel_quantize_fonts) - } - } - - pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) { - unsafe { - CGContextSetAllowsFontSubpixelPositioning(self.as_ptr(), allows_font_subpixel_positioning) - } - } - - pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) { - unsafe { - CGContextSetShouldSubpixelPositionFonts(self.as_ptr(), should_subpixel_position_fonts) - } - } - - pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) { - unsafe { - CGContextSetTextDrawingMode(self.as_ptr(), mode) - } - } - - pub fn set_line_cap(&self, cap: CGLineCap) { - unsafe { - CGContextSetLineCap(self.as_ptr(), cap) - } - } - - pub fn set_line_dash(&self, phase: CGFloat, lengths: &[CGFloat]) { - unsafe { - CGContextSetLineDash(self.as_ptr(), phase, lengths.as_ptr(), lengths.len()) - } - } - - pub fn set_line_join(&self, join: CGLineJoin) { - unsafe { - CGContextSetLineJoin(self.as_ptr(), join) - } - } - - pub fn set_line_width(&self, width: CGFloat) { - unsafe { - CGContextSetLineWidth(self.as_ptr(), width) - } - } - - pub fn set_miter_limit(&self, limit: CGFloat) { - unsafe { - CGContextSetMiterLimit(self.as_ptr(), limit) - } - } - - pub fn add_path(&self, path: &CGPathRef) { - unsafe { - CGContextAddPath(self.as_ptr(), path.as_ptr()); - } - } - - pub fn add_curve_to_point(&self, - cp1x: CGFloat, - cp1y: CGFloat, - cp2x: CGFloat, - cp2y: CGFloat, - x: CGFloat, - y: CGFloat) { - unsafe { - CGContextAddCurveToPoint(self.as_ptr(), - cp1x, cp1y, - cp2x, cp2y, - x, y); - } - } - - pub fn add_quad_curve_to_point(&self, - cpx: CGFloat, - cpy: CGFloat, - x: CGFloat, - y: CGFloat) { - unsafe { - CGContextAddQuadCurveToPoint(self.as_ptr(), - cpx, cpy, - x, y); - } - } - - pub fn add_line_to_point(&self, x: CGFloat, y: CGFloat) { - unsafe { - CGContextAddLineToPoint(self.as_ptr(), x, y); - } - } - - pub fn begin_path(&self) { - unsafe { - CGContextBeginPath(self.as_ptr()); - } - } - - pub fn close_path(&self) { - unsafe { - CGContextClosePath(self.as_ptr()); - } - } - - pub fn move_to_point(&self, x: CGFloat, y: CGFloat) { - unsafe { - CGContextMoveToPoint(self.as_ptr(), x, y); - } - } - - pub fn clip(&self) { - unsafe { - CGContextClip(self.as_ptr()); - } - } - - pub fn eo_clip(&self) { - unsafe { - CGContextEOClip(self.as_ptr()); - } - } - - pub fn draw_path(&self, mode: CGPathDrawingMode) { - unsafe { - CGContextDrawPath(self.as_ptr(), mode); - } - } - - pub fn fill_path(&self) { - unsafe { - CGContextFillPath(self.as_ptr()); - } - } - - pub fn eo_fill_path(&self) { - unsafe { - CGContextEOFillPath(self.as_ptr()); - } - } - - pub fn stroke_path(&self) { - unsafe { - CGContextStrokePath(self.as_ptr()); - } - } - - pub fn fill_rect(&self, rect: CGRect) { - unsafe { - CGContextFillRect(self.as_ptr(), rect) - } - } - - pub fn fill_rects(&self, rects: &[CGRect]) { - unsafe { - CGContextFillRects(self.as_ptr(), rects.as_ptr(), rects.len()) - } - } - - pub fn clear_rect(&self, rect: CGRect) { - unsafe { - CGContextClearRect(self.as_ptr(), rect) - } - } - - pub fn stroke_rect(&self, rect: CGRect) { - unsafe { - CGContextStrokeRect(self.as_ptr(), rect) - } - } - - pub fn stroke_rect_with_width(&self, rect: CGRect, width: CGFloat) { - unsafe { - CGContextStrokeRectWithWidth(self.as_ptr(), rect, width) - } - } - - pub fn clip_to_rect(&self, rect: CGRect) { - unsafe { - CGContextClipToRect(self.as_ptr(), rect) - } - } - - pub fn clip_to_rects(&self, rects: &[CGRect]) { - unsafe { - CGContextClipToRects(self.as_ptr(), rects.as_ptr(), rects.len()) - } - } - - pub fn replace_path_with_stroked_path(&self) { - unsafe { - CGContextReplacePathWithStrokedPath(self.as_ptr()) - } - } - - pub fn fill_ellipse_in_rect(&self, rect: CGRect) { - unsafe { - CGContextFillEllipseInRect(self.as_ptr(), rect) - } - } - - pub fn stroke_ellipse_in_rect(&self, rect: CGRect) { - unsafe { - CGContextStrokeEllipseInRect(self.as_ptr(), rect) - } - } - - pub fn stroke_line_segments(&self, points: &[CGPoint]) { - unsafe { - CGContextStrokeLineSegments(self.as_ptr(), points.as_ptr(), points.len()) - } - } - - pub fn draw_image(&self, rect: CGRect, image: &CGImage) { - unsafe { - CGContextDrawImage(self.as_ptr(), rect, image.as_ptr()); - } - } - - pub fn create_image(&self) -> Option { - let image = unsafe { CGBitmapContextCreateImage(self.as_ptr()) }; - if !image.is_null() { - Some(unsafe { CGImage::from_ptr(image) }) - } else { - None - } - } - - pub fn set_font(&self, font: &CGFont) { - unsafe { - CGContextSetFont(self.as_ptr(), font.as_ptr()) - } - } - - pub fn set_font_size(&self, size: CGFloat) { - unsafe { - CGContextSetFontSize(self.as_ptr(), size) - } - } - - pub fn set_text_matrix(&self, t: &CGAffineTransform) { - unsafe { - CGContextSetTextMatrix(self.as_ptr(), *t) - } - } - - pub fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) { - unsafe { - let count = cmp::min(glyphs.len(), positions.len()); - CGContextShowGlyphsAtPositions(self.as_ptr(), - glyphs.as_ptr(), - positions.as_ptr(), - count) - } - } - - pub fn save(&self) { - unsafe { - CGContextSaveGState(self.as_ptr()); - } - } - - pub fn restore(&self) { - unsafe { - CGContextRestoreGState(self.as_ptr()); - } - } - - pub fn translate(&self, tx: CGFloat, ty: CGFloat) { - unsafe { - CGContextTranslateCTM(self.as_ptr(), tx, ty); - } - } - - pub fn scale(&self, sx: CGFloat, sy: CGFloat) { - unsafe { - CGContextScaleCTM(self.as_ptr(), sx, sy); - } - } - - pub fn rotate(&self, angle: CGFloat) { - unsafe { - CGContextRotateCTM(self.as_ptr(), angle); - } - } - - pub fn get_ctm(&self) -> CGAffineTransform { - unsafe { - CGContextGetCTM(self.as_ptr()) - } - } - - pub fn concat_ctm(&self, transform: CGAffineTransform) { - unsafe { - CGContextConcatCTM(self.as_ptr(), transform) - } - } -} - -#[test] -fn create_bitmap_context_test() { - use geometry::*; - - let cs = CGColorSpace::create_device_rgb(); - let ctx = CGContext::create_bitmap_context(None, - 16, 8, - 8, 0, - &cs, - ::base::kCGImageAlphaPremultipliedLast); - ctx.set_rgb_fill_color(1.,0.,1.,1.); - ctx.set_miter_limit(4.); - ctx.fill_rect(CGRect::new(&CGPoint::new(0.,0.), &CGSize::new(8.,8.))); - let img = ctx.create_image().unwrap(); - assert_eq!(16, img.width()); - assert_eq!(8, img.height()); - assert_eq!(8, img.bits_per_component()); - assert_eq!(32, img.bits_per_pixel()); - let data = img.data(); - assert_eq!(255, data.bytes()[0]); - assert_eq!(0, data.bytes()[1]); - assert_eq!(255, data.bytes()[2]); - assert_eq!(255, data.bytes()[3]); -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - fn CGBitmapContextCreate(data: *mut c_void, - width: size_t, - height: size_t, - bitsPerComponent: size_t, - bytesPerRow: size_t, - space: ::sys::CGColorSpaceRef, - bitmapInfo: u32) - -> ::sys::CGContextRef; - fn CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void; - fn CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t; - fn CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t; - fn CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t; - fn CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef; - fn CGContextGetTypeID() -> CFTypeID; - fn CGContextGetClipBoundingBox(c: ::sys::CGContextRef) -> CGRect; - fn CGContextFlush(c: ::sys::CGContextRef); - fn CGContextSetBlendMode(c: ::sys::CGContextRef, blendMode: CGBlendMode); - fn CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool); - fn CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool); - fn CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int); - fn CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool); - fn CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool); - fn CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef, - allowsFontSubpixelQuantization: bool); - fn CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef, - shouldSubpixelQuantizeFonts: bool); - fn CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef, - allowsFontSubpixelPositioning: bool); - fn CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef, - shouldSubpixelPositionFonts: bool); - fn CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode); - fn CGContextSetFillColorWithColor(c: ::sys::CGContextRef, color: *const c_void); - fn CGContextSetLineCap(c: ::sys::CGContextRef, cap: CGLineCap); - fn CGContextSetLineDash(c: ::sys::CGContextRef, phase: CGFloat, lengths: *const CGFloat, count: size_t); - fn CGContextSetLineJoin(c: ::sys::CGContextRef, join: CGLineJoin); - fn CGContextSetLineWidth(c: ::sys::CGContextRef, width: CGFloat); - fn CGContextSetMiterLimit(c: ::sys::CGContextRef, limit: CGFloat); - - fn CGContextAddPath(c: ::sys::CGContextRef, path: ::sys::CGPathRef); - fn CGContextAddCurveToPoint(c: ::sys::CGContextRef, - cp1x: CGFloat, - cp1y: CGFloat, - cp2x: CGFloat, - cp2y: CGFloat, - x: CGFloat, - y: CGFloat); - fn CGContextAddQuadCurveToPoint(c: ::sys::CGContextRef, - cpx: CGFloat, - cpy: CGFloat, - x: CGFloat, - y: CGFloat); - fn CGContextAddLineToPoint(c: ::sys::CGContextRef, - x: CGFloat, - y: CGFloat); - fn CGContextBeginPath(c: ::sys::CGContextRef); - fn CGContextClosePath(c: ::sys::CGContextRef); - fn CGContextMoveToPoint(c: ::sys::CGContextRef, - x: CGFloat, - y: CGFloat); - fn CGContextDrawPath(c: ::sys::CGContextRef, mode: CGPathDrawingMode); - fn CGContextFillPath(c: ::sys::CGContextRef); - fn CGContextEOFillPath(c: ::sys::CGContextRef); - fn CGContextClip(c: ::sys::CGContextRef); - fn CGContextEOClip(c: ::sys::CGContextRef); - fn CGContextStrokePath(c: ::sys::CGContextRef); - fn CGContextSetRGBFillColor(context: ::sys::CGContextRef, - red: CGFloat, - green: CGFloat, - blue: CGFloat, - alpha: CGFloat); - fn CGContextSetRGBStrokeColor(context: ::sys::CGContextRef, - red: CGFloat, - green: CGFloat, - blue: CGFloat, - alpha: CGFloat); - fn CGContextSetGrayFillColor(context: ::sys::CGContextRef, gray: CGFloat, alpha: CGFloat); - fn CGContextClearRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextFillRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextFillRects(context: ::sys::CGContextRef, - rects: *const CGRect, - count: size_t); - fn CGContextStrokeRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextStrokeRectWithWidth(context: ::sys::CGContextRef, - rect: CGRect, - width: CGFloat); - fn CGContextClipToRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextClipToRects(context: ::sys::CGContextRef, - rects: *const CGRect, - count: size_t); - fn CGContextReplacePathWithStrokedPath(context: ::sys::CGContextRef); - fn CGContextFillEllipseInRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextStrokeEllipseInRect(context: ::sys::CGContextRef, - rect: CGRect); - fn CGContextStrokeLineSegments(context: ::sys::CGContextRef, - points: *const CGPoint, - count: size_t); - fn CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef); - fn CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef); - fn CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat); - fn CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform); - fn CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef, - glyphs: *const CGGlyph, - positions: *const CGPoint, - count: size_t); - - fn CGContextSaveGState(c: ::sys::CGContextRef); - fn CGContextRestoreGState(c: ::sys::CGContextRef); - fn CGContextTranslateCTM(c: ::sys::CGContextRef, tx: CGFloat, ty: CGFloat); - fn CGContextScaleCTM(c: ::sys::CGContextRef, sx: CGFloat, sy: CGFloat); - fn CGContextRotateCTM(c: ::sys::CGContextRef, angle: CGFloat); - fn CGContextGetCTM(c: ::sys::CGContextRef) -> CGAffineTransform; - fn CGContextConcatCTM(c: ::sys::CGContextRef, transform: CGAffineTransform); -} - diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/event.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/event.rs deleted file mode 100644 index 770ca08..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/event.rs +++ /dev/null @@ -1,669 +0,0 @@ -#![allow(non_upper_case_globals)] - -use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; -use geometry::CGPoint; -use event_source::CGEventSource; - -use libc; - -use foreign_types::ForeignType; - -pub type CGEventField = u32; -pub type CGKeyCode = u16; -pub type CGScrollEventUnit = u32; - -/// Flags for events -/// -/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) -bitflags! { - #[repr(C)] - pub struct CGEventFlags: u64 { - const CGEventFlagNull = 0; - - // Device-independent modifier key bits. - const CGEventFlagAlphaShift = 0x00010000; - const CGEventFlagShift = 0x00020000; - const CGEventFlagControl = 0x00040000; - const CGEventFlagAlternate = 0x00080000; - const CGEventFlagCommand = 0x00100000; - - // Special key identifiers. - const CGEventFlagHelp = 0x00400000; - const CGEventFlagSecondaryFn = 0x00800000; - - // Identifies key events from numeric keypad area on extended keyboards. - const CGEventFlagNumericPad = 0x00200000; - - // Indicates if mouse/pen movement events are not being coalesced - const CGEventFlagNonCoalesced = 0x00000100; - } -} - -/// Key codes for keys that are independent of keyboard layout. -/// -/// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h) -#[repr(C)] -pub struct KeyCode; -impl KeyCode { - pub const RETURN: CGKeyCode = 0x24; - pub const TAB: CGKeyCode = 0x30; - pub const SPACE: CGKeyCode = 0x31; - pub const DELETE: CGKeyCode = 0x33; - pub const ESCAPE: CGKeyCode = 0x35; - pub const COMMAND: CGKeyCode = 0x37; - pub const SHIFT: CGKeyCode = 0x38; - pub const CAPS_LOCK: CGKeyCode = 0x39; - pub const OPTION: CGKeyCode = 0x3A; - pub const CONTROL: CGKeyCode = 0x3B; - pub const RIGHT_COMMAND: CGKeyCode = 0x36; - pub const RIGHT_SHIFT: CGKeyCode = 0x3C; - pub const RIGHT_OPTION: CGKeyCode = 0x3D; - pub const RIGHT_CONTROL: CGKeyCode = 0x3E; - pub const FUNCTION: CGKeyCode = 0x3F; - pub const VOLUME_UP: CGKeyCode = 0x48; - pub const VOLUME_DOWN: CGKeyCode = 0x49; - pub const MUTE: CGKeyCode = 0x4A; - pub const F1: CGKeyCode = 0x7A; - pub const F2: CGKeyCode = 0x78; - pub const F3: CGKeyCode = 0x63; - pub const F4: CGKeyCode = 0x76; - pub const F5: CGKeyCode = 0x60; - pub const F6: CGKeyCode = 0x61; - pub const F7: CGKeyCode = 0x62; - pub const F8: CGKeyCode = 0x64; - pub const F9: CGKeyCode = 0x65; - pub const F10: CGKeyCode = 0x6D; - pub const F11: CGKeyCode = 0x67; - pub const F12: CGKeyCode = 0x6F; - pub const F13: CGKeyCode = 0x69; - pub const F14: CGKeyCode = 0x6B; - pub const F15: CGKeyCode = 0x71; - pub const F16: CGKeyCode = 0x6A; - pub const F17: CGKeyCode = 0x40; - pub const F18: CGKeyCode = 0x4F; - pub const F19: CGKeyCode = 0x50; - pub const F20: CGKeyCode = 0x5A; - pub const HELP: CGKeyCode = 0x72; - pub const HOME: CGKeyCode = 0x73; - pub const PAGE_UP: CGKeyCode = 0x74; - pub const FORWARD_DELETE: CGKeyCode = 0x75; - pub const END: CGKeyCode = 0x77; - pub const PAGE_DOWN: CGKeyCode = 0x79; - pub const LEFT_ARROW: CGKeyCode = 0x7B; - pub const RIGHT_ARROW: CGKeyCode = 0x7C; - pub const DOWN_ARROW: CGKeyCode = 0x7D; - pub const UP_ARROW: CGKeyCode = 0x7E; -} - -#[repr(C)] -pub struct ScrollEventUnit {} -impl ScrollEventUnit { - pub const PIXEL: CGScrollEventUnit = 0; - pub const LINE: CGScrollEventUnit = 1; -} - -/// Constants that specify the different types of input events. -/// -/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) -#[repr(u32)] -#[derive(Clone, Copy, Debug)] -pub enum CGEventType { - Null = 0, - - // Mouse events. - LeftMouseDown = 1, - LeftMouseUp = 2, - RightMouseDown = 3, - RightMouseUp = 4, - MouseMoved = 5, - LeftMouseDragged = 6, - RightMouseDragged = 7, - - // Keyboard events. - KeyDown = 10, - KeyUp = 11, - FlagsChanged = 12, - - // Specialized control devices. - ScrollWheel = 22, - TabletPointer = 23, - TabletProximity = 24, - OtherMouseDown = 25, - OtherMouseUp = 26, - OtherMouseDragged = 27, - - // Out of band event types. These are delivered to the event tap callback - // to notify it of unusual conditions that disable the event tap. - TapDisabledByTimeout = 0xFFFFFFFE, - TapDisabledByUserInput = 0xFFFFFFFF, -} - -/// Constants used as keys to access specialized fields in low-level events. -/// -/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield) -pub struct EventField; -impl EventField { - /// Key to access an integer field that contains the mouse button event - /// number. Matching mouse-down and mouse-up events will have the same - /// event number. - pub const MOUSE_EVENT_NUMBER: CGEventField = 0; - - /// Key to access an integer field that contains the mouse button click - /// state. A click state of 1 represents a single click. A click state of - /// 2 represents a double-click. A click state of 3 represents a - /// triple-click. - pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1; - - /// Key to access a double field that contains the mouse button pressure. - /// The pressure value may range from 0 to 1, with 0 representing the - /// mouse being up. This value is commonly set by tablet pens mimicking a - /// mouse. - pub const MOUSE_EVENT_PRESSURE: CGEventField = 2; - - /// Key to access an integer field that contains the mouse button number. - pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3; - - /// Key to access an integer field that contains the horizontal mouse - /// delta since the last mouse movement event. - pub const MOUSE_EVENT_DELTA_X: CGEventField = 4; - - /// Key to access an integer field that contains the vertical mouse delta - /// since the last mouse movement event. - pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5; - - /// Key to access an integer field. The value is non-zero if the event - /// should be ignored by the Inkwell subsystem. - pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6; - - /// Key to access an integer field that encodes the mouse event subtype as - /// a `kCFNumberIntType'. - pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7; - - /// Key to access an integer field, non-zero when this is an autorepeat of - /// a key-down, and zero otherwise. - pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8; - - /// Key to access an integer field that contains the virtual keycode of the - /// key-down or key-up event. - pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9; - - /// Key to access an integer field that contains the keyboard type - /// identifier. - pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10; - - /// Key to access an integer field that contains scrolling data. This field - /// typically contains the change in vertical position since the last - /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse - /// scroller. - pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11; - - /// Key to access an integer field that contains scrolling data. This field - /// typically contains the change in horizontal position since the last - /// scrolling event from a Mighty Mouse scroller. - pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12; - - /// Key to access a field that contains scrolling data. The scrolling data - /// represents a line-based or pixel-based change in vertical position - /// since the last scrolling event from a Mighty Mouse scroller or a - /// single-wheel mouse scroller. The scrolling data uses a fixed-point - /// 16.16 signed integer format. If this key is passed to - /// `CGEventGetDoubleValueField', the fixed-point value is converted to a - /// double value. - pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93; - - /// Key to access a field that contains scrolling data. The scrolling data - /// represents a line-based or pixel-based change in horizontal position - /// since the last scrolling event from a Mighty Mouse scroller. The - /// scrolling data uses a fixed-point 16.16 signed integer format. If this - /// key is passed to `CGEventGetDoubleValueField', the fixed-point value is - /// converted to a double value. - pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94; - - /// Key to access an integer field that contains pixel-based scrolling - /// data. The scrolling data represents the change in vertical position - /// since the last scrolling event from a Mighty Mouse scroller or a - /// single-wheel mouse scroller. - pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96; - - /// Key to access an integer field that contains pixel-based scrolling - /// data. The scrolling data represents the change in horizontal position - /// since the last scrolling event from a Mighty Mouse scroller. - pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97; - - /// Key to access an integer field that indicates whether the event should - /// be ignored by the Inkwell subsystem. If the value is non-zero, the - /// event should be ignored. - pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14; - - /// Key to access an integer field that contains the absolute X coordinate - /// in tablet space at full tablet resolution. - pub const TABLET_EVENT_POINT_X: CGEventField = 15; - - /// Key to access an integer field that contains the absolute Y coordinate - /// in tablet space at full tablet resolution. - pub const TABLET_EVENT_POINT_Y: CGEventField = 16; - - /// Key to access an integer field that contains the absolute Z coordinate - /// in tablet space at full tablet resolution. - pub const TABLET_EVENT_POINT_Z: CGEventField = 17; - - /// Key to access an integer field that contains the tablet button state. - /// Bit 0 is the first button, and a set bit represents a closed or pressed - /// button. Up to 16 buttons are supported. - pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18; - - /// Key to access a double field that contains the tablet pen pressure. A - /// value of 0.0 represents no pressure, and 1.0 represents maximum - /// pressure. - pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19; - - /// Key to access a double field that contains the horizontal tablet pen - /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. - pub const TABLET_EVENT_TILT_X: CGEventField = 20; - - /// Key to access a double field that contains the vertical tablet pen - /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. - pub const TABLET_EVENT_TILT_Y: CGEventField = 21; - - /// Key to access a double field that contains the tablet pen rotation. - pub const TABLET_EVENT_ROTATION: CGEventField = 22; - - /// Key to access a double field that contains the tangential pressure on - /// the device. A value of 0.0 represents no pressure, and 1.0 represents - /// maximum pressure. - pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23; - - /// Key to access an integer field that contains the system-assigned unique - /// device ID. - pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24; - - /// Key to access an integer field that contains a vendor-specified value. - pub const TABLET_EVENT_VENDOR_1: CGEventField = 25; - - /// Key to access an integer field that contains a vendor-specified value. - pub const TABLET_EVENT_VENDOR_2: CGEventField = 26; - - /// Key to access an integer field that contains a vendor-specified value. - pub const TABLET_EVENT_VENDOR_3: CGEventField = 27; - - /// Key to access an integer field that contains the vendor-defined ID, - /// typically the USB vendor ID. - pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28; - - /// Key to access an integer field that contains the vendor-defined tablet - /// ID, typically the USB product ID. - pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29; - - /// Key to access an integer field that contains the vendor-defined ID of - /// the pointing device. - pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30; - - /// Key to access an integer field that contains the system-assigned - /// device ID. - pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31; - - /// Key to access an integer field that contains the system-assigned - /// unique tablet ID. - pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32; - - /// Key to access an integer field that contains the vendor-assigned - /// pointer type. - pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33; - - /// Key to access an integer field that contains the vendor-defined - /// pointer serial number. - pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34; - - /// Key to access an integer field that contains the vendor-defined unique - /// ID. - pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35; - - /// Key to access an integer field that contains the device capabilities - /// mask. - pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36; - - /// Key to access an integer field that contains the pointer type. - pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37; - - /// Key to access an integer field that indicates whether the pen is in - /// proximity to the tablet. The value is non-zero if the pen is in - /// proximity to the tablet and zero when leaving the tablet. - pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38; - - /// Key to access a field that contains the event target process serial - /// number. The value is a 64-bit value. - pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39; - - /// Key to access a field that contains the event target Unix process ID. - pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40; - - /// Key to access a field that contains the event source Unix process ID. - pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41; - - /// Key to access a field that contains the event source user-supplied - /// data, up to 64 bits. - pub const EVENT_SOURCE_USER_DATA: CGEventField = 42; - - /// Key to access a field that contains the event source Unix effective UID. - pub const EVENT_SOURCE_USER_ID: CGEventField = 43; - - /// Key to access a field that contains the event source Unix effective - /// GID. - pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44; - - /// Key to access a field that contains the event source state ID used to - /// create this event. - pub const EVENT_SOURCE_STATE_ID: CGEventField = 45; - - /// Key to access an integer field that indicates whether a scrolling event - /// contains continuous, pixel-based scrolling data. The value is non-zero - /// when the scrolling data is pixel-based and zero when the scrolling data - /// is line-based. - pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88; - - /// Added in 10.5; made public in 10.7. - pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91; - pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92; -} - -// Constants that specify buttons on a one, two, or three-button mouse. -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGMouseButton { - Left, - Right, - Center, -} - -/// Possible tapping points for events. -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub enum CGEventTapLocation { - HID, - Session, - AnnotatedSession, -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGEvent; - fn drop = |p| CFRelease(p as *mut _); - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGEvent; - pub struct CGEventRef; -} - -impl CGEvent { - pub fn type_id() -> CFTypeID { - unsafe { - CGEventGetTypeID() - } - } - - pub fn new(source: CGEventSource) -> Result { - unsafe { - let event_ref = CGEventCreate(source.as_ptr()); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - pub fn new_keyboard_event( - source: CGEventSource, - keycode: CGKeyCode, - keydown: bool - ) -> Result { - unsafe { - let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - pub fn new_mouse_event( - source: CGEventSource, - mouse_type: CGEventType, - mouse_cursor_position: CGPoint, - mouse_button: CGMouseButton - ) -> Result { - unsafe { - let event_ref = CGEventCreateMouseEvent(source.as_ptr(), mouse_type, - mouse_cursor_position, mouse_button); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - #[cfg(feature = "highsierra")] - pub fn new_scroll_event( - source: CGEventSource, - units: CGScrollEventUnit, - wheel_count: u32, - wheel1: i32, - wheel2: i32, - wheel3: i32, - ) -> Result { - unsafe { - let event_ref = CGEventCreateScrollWheelEvent2( - source.as_ptr(), - units, - wheel_count, - wheel1, - wheel2, - wheel3, - ); - if !event_ref.is_null() { - Ok(Self::from_ptr(event_ref)) - } else { - Err(()) - } - } - } - - pub fn post(&self, tap_location: CGEventTapLocation) { - unsafe { - CGEventPost(tap_location, self.as_ptr()); - } - } - - pub fn location(&self) -> CGPoint { - unsafe { - CGEventGetLocation(self.as_ptr()) - } - } - - #[cfg(feature = "elcapitan")] - pub fn post_to_pid(&self, pid: libc::pid_t) { - unsafe { - CGEventPostToPid(pid, self.as_ptr()); - } - } - - pub fn set_flags(&self, flags: CGEventFlags) { - unsafe { - CGEventSetFlags(self.as_ptr(), flags); - } - } - - pub fn get_flags(&self) -> CGEventFlags { - unsafe { - CGEventGetFlags(self.as_ptr()) - } - } - - pub fn set_type(&self, event_type: CGEventType) { - unsafe { - CGEventSetType(self.as_ptr(), event_type); - } - } - - pub fn get_type(&self) -> CGEventType { - unsafe { - CGEventGetType(self.as_ptr()) - } - } - - pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) { - let buflen = buf.len() as libc::c_ulong; - unsafe { - CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr()); - } - } - - pub fn set_string(&self, string: &str) { - let buf: Vec = string.encode_utf16().collect(); - self.set_string_from_utf16_unchecked(&buf); - } - - pub fn get_integer_value_field(&self, field: CGEventField) -> i64 { - unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) } - } - - pub fn set_integer_value_field(&self, field: CGEventField, value: i64) { - unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) } - } - - pub fn get_double_value_field(&self, field: CGEventField) -> f64 { - unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) } - } - - pub fn set_double_value_field(&self, field: CGEventField, value: f64) { - unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) } - } -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - /// Return the type identifier for the opaque type `CGEventRef'. - fn CGEventGetTypeID() -> CFTypeID; - - /// Return a new event using the event source `source'. If `source' is NULL, - /// the default source is used. - fn CGEventCreate(source: ::sys::CGEventSourceRef) -> ::sys::CGEventRef; - - /// Return a new keyboard event. - /// - /// The event source may be taken from another event, or may be NULL. Based - /// on the virtual key code values entered, the appropriate key down, key up, - /// or flags changed events are generated. - /// - /// All keystrokes needed to generate a character must be entered, including - /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z', - /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT - /// and 'z' key must be released: - fn CGEventCreateKeyboardEvent(source: ::sys::CGEventSourceRef, keycode: CGKeyCode, - keydown: bool) -> ::sys::CGEventRef; - - /// Return a new mouse event. - /// - /// The event source may be taken from another event, or may be NULL. - /// `mouseType' should be one of the mouse event types. `mouseCursorPosition' - /// should be the position of the mouse cursor in global coordinates. - /// `mouseButton' should be the button that's changing state; `mouseButton' - /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown', - /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'. - /// - /// The current implementation of the event system supports a maximum of - /// thirty-two buttons. Mouse button 0 is the primary button on the mouse. - /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is - /// the center button, and the remaining buttons are in USB device order. - fn CGEventCreateMouseEvent(source: ::sys::CGEventSourceRef, mouseType: CGEventType, - mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> ::sys::CGEventRef; - - /// A non-variadic variant version of CGEventCreateScrollWheelEvent. - /// - /// Returns a new Quartz scrolling event. - /// - /// This function allows you to create a scrolling event and customize the - /// event before posting it to the event system. - #[cfg(feature = "highsierra")] - fn CGEventCreateScrollWheelEvent2( - source: ::sys::CGEventSourceRef, - units: CGScrollEventUnit, - wheelCount: u32, - wheel1: i32, - wheel2: i32, - wheel3: i32, - ) -> ::sys::CGEventRef; - - /// Post an event into the event stream at a specified location. - /// - /// This function posts the specified event immediately before any event taps - /// instantiated for that location, and the event passes through any such - /// taps. - fn CGEventPost(tapLocation: CGEventTapLocation, event: ::sys::CGEventRef); - - #[cfg(feature = "elcapitan")] - /// Post an event to a specified process ID - fn CGEventPostToPid(pid: libc::pid_t, event: ::sys::CGEventRef); - - /// Set the event flags of an event. - fn CGEventSetFlags(event: ::sys::CGEventRef, flags: CGEventFlags); - - /// Return the event flags of an event. - fn CGEventGetFlags(event: ::sys::CGEventRef) -> CGEventFlags; - - /// Return the location of an event in global display coordinates. - /// CGPointZero is returned if event is not a valid ::sys::CGEventRef. - fn CGEventGetLocation(event: ::sys::CGEventRef) -> CGPoint; - - /// Set the event type of an event. - fn CGEventSetType(event: ::sys::CGEventRef, eventType: CGEventType); - - /// Return the event type of an event (left mouse down, for example). - fn CGEventGetType(event: ::sys::CGEventRef) -> CGEventType; - - /// Set the Unicode string associated with a keyboard event. - /// - /// By default, the system translates the virtual key code in a keyboard - /// event into a Unicode string based on the keyboard ID in the event - /// source. This function allows you to manually override this string. - /// Note that application frameworks may ignore the Unicode string in a - /// keyboard event and do their own translation based on the virtual - /// keycode and perceived event state. - fn CGEventKeyboardSetUnicodeString(event: ::sys::CGEventRef, - length: libc::c_ulong, - string: *const u16); - - /// Return the integer value of a field in an event. - fn CGEventGetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField) -> i64; - - /// Set the integer value of a field in an event. - /// - /// Before calling this function, the event type must be set using a typed - /// event creation function such as `CGEventCreateMouseEvent', or by - /// calling `CGEventSetType'. - /// - /// If you are creating a mouse event generated by a tablet, call this - /// function and specify the field `kCGMouseEventSubtype' with a value of - /// `kCGEventMouseSubtypeTabletPoint' or - /// `kCGEventMouseSubtypeTabletProximity' before setting other parameters. - fn CGEventSetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField, value: i64); - - /// Return the floating-point value of a field in an event. - /// - /// In cases where the field value is represented within the event by a fixed - /// point number or an integer, the result is scaled to the appropriate range - /// as part of creating the floating-point representation. - fn CGEventGetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField) -> f64; - - /// Set the floating-point value of a field in an event. - /// - /// Before calling this function, the event type must be set using a typed - /// event creation function such as `CGEventCreateMouseEvent', or by calling - /// `CGEventSetType'. - /// - /// In cases where the field’s value is represented within the event by a - /// fixed point number or integer, the value parameter is scaled as needed - /// and converted to the appropriate type. - fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64); -} diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/geometry.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/geometry.rs deleted file mode 100644 index c3a7bda..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/geometry.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use base::CGFloat; -use core_foundation::base::TCFType; -use core_foundation::dictionary::CFDictionary; - -pub const CG_ZERO_POINT: CGPoint = CGPoint { - x: 0.0, - y: 0.0, -}; - -pub const CG_ZERO_SIZE: CGSize = CGSize { - width: 0.0, - height: 0.0, -}; - -pub const CG_ZERO_RECT: CGRect = CGRect { - origin: CG_ZERO_POINT, - size: CG_ZERO_SIZE, -}; - -pub const CG_AFFINE_TRANSFORM_IDENTITY: CGAffineTransform = CGAffineTransform { - a: 1.0, b: 0.0, - c: 0.0, d: 1.0, - tx: 0.0, ty: 0.0, -}; - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct CGSize { - pub width: CGFloat, - pub height: CGFloat, -} - -impl CGSize { - #[inline] - pub fn new(width: CGFloat, height: CGFloat) -> CGSize { - CGSize { - width: width, - height: height, - } - } - - #[inline] - pub fn apply_transform(&self, t: &CGAffineTransform) -> CGSize { - unsafe { - ffi::CGSizeApplyAffineTransform(*self, *t) - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct CGPoint { - pub x: CGFloat, - pub y: CGFloat, -} - -impl CGPoint { - #[inline] - pub fn new(x: CGFloat, y: CGFloat) -> CGPoint { - CGPoint { - x: x, - y: y, - } - } - - #[inline] - pub fn apply_transform(&self, t: &CGAffineTransform) -> CGPoint { - unsafe { - ffi::CGPointApplyAffineTransform(*self, *t) - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CGRect { - pub origin: CGPoint, - pub size: CGSize -} - -impl CGRect { - #[inline] - pub fn new(origin: &CGPoint, size: &CGSize) -> CGRect { - CGRect { - origin: *origin, - size: *size, - } - } - - #[inline] - pub fn inset(&self, size: &CGSize) -> CGRect { - unsafe { - ffi::CGRectInset(*self, size.width, size.height) - } - } - - #[inline] - pub fn from_dict_representation(dict: &CFDictionary) -> Option { - let mut rect = CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(0., 0.)); - let result = unsafe { - ffi::CGRectMakeWithDictionaryRepresentation(dict.as_concrete_TypeRef(), &mut rect) - }; - if result == 0 { - None - } else { - Some(rect) - } - } - - #[inline] - pub fn is_empty(&self) -> bool { - unsafe { - // I use one, as it seems that `YES` is not available from this crate. - ffi::CGRectIsEmpty(*self) == 1 - } - } - - #[inline] - pub fn is_intersects(&self, other: &CGRect) -> bool { - unsafe { - // I use one, as it seems that `YES` is not available from this crate. - ffi::CGRectIntersectsRect(*self, *other) == 1 - } - } - - #[inline] - pub fn apply_transform(&self, t: &CGAffineTransform) -> CGRect { - unsafe { - ffi::CGRectApplyAffineTransform(*self, *t) - } - } -} - -impl PartialEq for CGRect { - #[inline] - fn eq(&self, other: &CGRect) -> bool { - unsafe { - ffi::CGRectEqualToRect(*self, *other) != 0 - } - } -} - -#[repr(C)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CGAffineTransform { - pub a: CGFloat, - pub b: CGFloat, - pub c: CGFloat, - pub d: CGFloat, - pub tx: CGFloat, - pub ty: CGFloat, -} - -impl CGAffineTransform { - #[inline] - pub fn new( - a: CGFloat, - b: CGFloat, - c: CGFloat, - d: CGFloat, - tx: CGFloat, - ty: CGFloat, - ) -> CGAffineTransform { - CGAffineTransform { a, b, c, d, tx, ty } - } - - #[inline] - pub fn invert(&self) -> CGAffineTransform { - unsafe { - ffi::CGAffineTransformInvert(*self) - } - } -} - -impl PartialEq for CGAffineTransform { - #[inline] - fn eq(&self, other: &CGAffineTransform) -> bool { - unsafe { - ffi::CGAffineTransformEqualToTransform(*self, *other) != 0 - } - } -} - -mod ffi { - use base::{CGFloat, boolean_t}; - use geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; - use core_foundation::dictionary::CFDictionaryRef; - - #[link(name = "CoreGraphics", kind = "framework")] - extern { - pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect; - pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef, - rect: *mut CGRect) -> boolean_t; - pub fn CGRectIsEmpty(rect: CGRect) -> boolean_t; - pub fn CGRectIntersectsRect(rect1: CGRect, rect2: CGRect) -> boolean_t; - pub fn CGRectEqualToRect(rect1: CGRect, rect2: CGRect) -> boolean_t; - - pub fn CGAffineTransformInvert(t: CGAffineTransform) -> CGAffineTransform; - pub fn CGAffineTransformEqualToTransform(t1: CGAffineTransform, - t2: CGAffineTransform) -> boolean_t; - - pub fn CGPointApplyAffineTransform(point: CGPoint, t: CGAffineTransform) -> CGPoint; - pub fn CGRectApplyAffineTransform(rect: CGRect, t: CGAffineTransform) -> CGRect; - pub fn CGSizeApplyAffineTransform(size: CGSize, t: CGAffineTransform) -> CGSize; - } -} - diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/image.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/image.rs deleted file mode 100644 index 84945e8..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/image.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::ptr; - -use base::CGFloat; -use core_foundation::base::{CFRetain, CFTypeID}; -use core_foundation::data::CFData; -use color_space::CGColorSpace; -use data_provider::{CGDataProviderRef, CGDataProvider}; -use geometry::CGRect; -use libc::size_t; -use foreign_types::{ForeignType, ForeignTypeRef}; - -#[repr(C)] -pub enum CGImageAlphaInfo { - CGImageAlphaNone, /* For example, RGB. */ - CGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ - CGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ - CGImageAlphaLast, /* For example, non-premultiplied RGBA */ - CGImageAlphaFirst, /* For example, non-premultiplied ARGB */ - CGImageAlphaNoneSkipLast, /* For example, RBGX. */ - CGImageAlphaNoneSkipFirst, /* For example, XRBG. */ - CGImageAlphaOnly /* No color data, alpha data only */ -} - -#[repr(C)] -pub enum CGImageByteOrderInfo { - CGImageByteOrderMask = 0x7000, - CGImageByteOrder16Little = (1 << 12), - CGImageByteOrder32Little = (2 << 12), - CGImageByteOrder16Big = (3 << 12), - CGImageByteOrder32Big = (4 << 12) -} - -foreign_type! { - #[doc(hidden)] - type CType = ::sys::CGImage; - fn drop = CGImageRelease; - fn clone = |p| CFRetain(p as *const _) as *mut _; - pub struct CGImage; - pub struct CGImageRef; -} - -impl CGImage { - pub fn new(width: size_t, - height: size_t, - bits_per_component: size_t, - bits_per_pixel: size_t, - bytes_per_row: size_t, - colorspace: &CGColorSpace, - bitmap_info: u32, - provider: &CGDataProvider, - should_interpolate: bool, - rendering_intent: u32) - -> Self { - unsafe { - let result = CGImageCreate(width, - height, - bits_per_component, - bits_per_pixel, - bytes_per_row, - colorspace.as_ptr(), - bitmap_info, - provider.as_ptr(), - ptr::null_mut(), - should_interpolate, - rendering_intent); - assert!(!result.is_null()); - Self::from_ptr(result) - } - } - - pub fn type_id() -> CFTypeID { - unsafe { - CGImageGetTypeID() - } - } -} - -impl CGImageRef { - pub fn width(&self) -> size_t { - unsafe { - CGImageGetWidth(self.as_ptr()) - } - } - - pub fn height(&self) -> size_t { - unsafe { - CGImageGetHeight(self.as_ptr()) - } - } - - pub fn bits_per_component(&self) -> size_t { - unsafe { - CGImageGetBitsPerComponent(self.as_ptr()) - } - } - - pub fn bits_per_pixel(&self) -> size_t { - unsafe { - CGImageGetBitsPerPixel(self.as_ptr()) - } - } - - pub fn bytes_per_row(&self) -> size_t { - unsafe { - CGImageGetBytesPerRow(self.as_ptr()) - } - } - - pub fn color_space(&self) -> CGColorSpace { - unsafe { - let cs = CGImageGetColorSpace(self.as_ptr()); - CFRetain(cs as *mut _); - CGColorSpace::from_ptr(cs) - } - } - - /// Returns the raw image bytes wrapped in `CFData`. Note, the returned `CFData` owns the - /// underlying buffer. - pub fn data(&self) -> CFData { - let data_provider = unsafe { - CGDataProviderRef::from_ptr(CGImageGetDataProvider(self.as_ptr())) - }; - data_provider.copy_data() - } - - /// Returns a cropped image. If the `rect` specifies a rectangle which lies outside of the - /// image bounds, the `None` is returned. - pub fn cropped(&self, rect: CGRect) -> Option { - let image_ptr = unsafe { CGImageCreateWithImageInRect(self.as_ptr(), rect) }; - if !image_ptr.is_null() { - Some(unsafe { CGImage::from_ptr(image_ptr) }) - } else { - None - } - } -} - -#[link(name = "CoreGraphics", kind = "framework")] -extern { - fn CGImageGetTypeID() -> CFTypeID; - fn CGImageGetWidth(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetHeight(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetBitsPerComponent(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetBitsPerPixel(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetBytesPerRow(image: ::sys::CGImageRef) -> size_t; - fn CGImageGetColorSpace(image: ::sys::CGImageRef) -> ::sys::CGColorSpaceRef; - fn CGImageGetDataProvider(image: ::sys::CGImageRef) -> ::sys::CGDataProviderRef; - fn CGImageRelease(image: ::sys::CGImageRef); - fn CGImageCreate(width: size_t, - height: size_t, - bitsPerComponent: size_t, - bitsPerPixel: size_t, - bytesPerRow: size_t, - space: ::sys::CGColorSpaceRef, - bitmapInfo: u32, - provider: ::sys::CGDataProviderRef, - decode: *const CGFloat, - shouldInterpolate: bool, - intent: u32) - -> ::sys::CGImageRef; - fn CGImageCreateWithImageInRect(image: ::sys::CGImageRef, rect: CGRect) -> ::sys::CGImageRef; - - //fn CGImageGetAlphaInfo(image: ::sys::CGImageRef) -> CGImageAlphaInfo; - //fn CGImageCreateCopyWithColorSpace(image: ::sys::CGImageRef, space: ::sys::CGColorSpaceRef) -> ::sys::CGImageRef -} diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/lib.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/lib.rs deleted file mode 100644 index 981883c..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 The Servo Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate libc; - -#[macro_use] -extern crate core_foundation; - -#[macro_use] -#[cfg(target_os = "macos")] -extern crate bitflags; - -#[macro_use] -extern crate foreign_types; - -pub mod base; -pub mod color; -pub mod color_space; -pub mod context; -pub mod data_provider; -#[cfg(target_os = "macos")] -pub mod display; -#[cfg(target_os = "macos")] -pub mod event; -#[cfg(target_os = "macos")] -pub mod event_source; -pub mod font; -pub mod geometry; -#[cfg(target_os = "macos")] -pub mod window; -#[cfg(target_os = "macos")] -pub mod private; -pub mod image; -pub mod path; -mod sys; diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/sys.rs b/third_party/cargo/vendor/core-graphics-0.19.0/src/sys.rs deleted file mode 100644 index ccf0625..0000000 --- a/third_party/cargo/vendor/core-graphics-0.19.0/src/sys.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::os::raw::c_void; - -pub enum CGImage {} -pub type CGImageRef = *mut CGImage; - -#[repr(C)] -pub struct __CGColor(c_void); - -pub type CGColorRef = *const __CGColor; - -pub enum CGColorSpace {} -pub type CGColorSpaceRef = *mut CGColorSpace; - -pub enum CGPath {} -pub type CGPathRef = *mut CGPath; - -pub enum CGDataProvider {} -pub type CGDataProviderRef = *mut CGDataProvider; - -pub enum CGFont {} -pub type CGFontRef = *mut CGFont; - -pub enum CGContext {} -pub type CGContextRef = *mut CGContext; - -#[cfg(target_os = "macos")] -mod macos { - pub enum CGEvent {} - pub type CGEventRef = *mut CGEvent; - - pub enum CGEventSource {} - pub type CGEventSourceRef = *mut CGEventSource; - - pub enum CGDisplayMode {} - pub type CGDisplayModeRef = *mut CGDisplayMode; -} - -#[cfg(target_os = "macos")] -pub use self::macos::*; diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/.cargo-checksum.json b/third_party/cargo/vendor/core-graphics-0.19.2/.cargo-checksum.json new file mode 100644 index 0000000..669a072 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"d2df7897d26d2497deffc96c41c4ee29453c47d4a431e2d68ed81ed6778bb575","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"6745c3c38183d2eda9b1fa265fb0a95018db5c110cbabc00b32327d951bbe2ea","src/base.rs":"76b969d3ad309d68b1fded68cc5b87bb98348249da4f05b7cdb65afa66c0cc01","src/color.rs":"4c8ec4ab828cbc1b2a1538a34a51f5b380927f2f1daf187dff6f732f57a43656","src/color_space.rs":"b3d7ee8a21703c789160867cb8eb2188bd1daa193e3d030f21adb6f1a6f872de","src/context.rs":"8bda7f9ecb5be768b09a29cc3b0a4f329f55d2a2ab74030d121610283862d833","src/data_provider.rs":"9e8a17075b1527f87111fd4102252e086bf9fde147483f21a661773e133f7c71","src/display.rs":"cc691712c3d27342ae97f04df6032d6f682570239ba51936fcc796c61bf08c8b","src/event.rs":"84d6035ab155e702be056f4f37d0cbb76ccfa8fb9277fcbfb42c7953d0cd3937","src/event_source.rs":"d55a4f5b5e62789325028febc51bbf54c74b15ab1a4e70c6ad749a2f9753e081","src/font.rs":"e1d2be7f909fd5876f3cd1649d54ef0a9d7dcd4151c027a25049be7084ca8a9f","src/geometry.rs":"3462993512aac012d102adcdee2fa10cfd8b6cf6ae6f16401322a58b11c20473","src/gradient.rs":"8ee8661706f36914d08e903840c4f07414b38ba40ea4a482d34b900ac6ac7cf9","src/image.rs":"a5a5df8c0f310455f038eeb16688015f481688cb417f8e8f424a4c1d2a1cdd57","src/lib.rs":"401bf6e0c44eead94fc421a398eb90006c8fc5c406b022ae2680981cb629ce89","src/path.rs":"c429afeaed999b02ac00f89a867b5fc64f1e223039079a4e0529306b734ff117","src/private.rs":"da3fd61338bab2d8e26aa5433b2e18ecd2a0a408c62e1ac2b33a0f87f2dad88a","src/sys.rs":"72cd460e499734a9394a8ec57dcb30ea0a15717452ff9fb343f22effa5d6d308","src/window.rs":"2f6c3dc958ae2c0c9e2fc5033300b96e60ed0abee9823ea1f03797d64df0911a"},"package":"b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/BUILD.bazel b/third_party/cargo/vendor/core-graphics-0.19.2/BUILD.bazel new file mode 100644 index 0000000..8e604a4 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/BUILD.bazel @@ -0,0 +1,58 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "core_graphics", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.19.2", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/core-foundation-0.7.0:core_foundation", + "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", + "//third_party/cargo/vendor/libc-0.2.82:libc", + ], +) diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/COPYRIGHT b/third_party/cargo/vendor/core-graphics-0.19.2/COPYRIGHT similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/COPYRIGHT rename to third_party/cargo/vendor/core-graphics-0.19.2/COPYRIGHT diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/Cargo.toml b/third_party/cargo/vendor/core-graphics-0.19.2/Cargo.toml new file mode 100644 index 0000000..a5940f6 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-graphics" +version = "0.19.2" +authors = ["The Servo Project Developers"] +description = "Bindings to Core Graphics for macOS" +homepage = "https://github.com/servo/core-graphics-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[dependencies.bitflags] +version = "1.0" + +[dependencies.core-foundation] +version = "0.7" + +[dependencies.foreign-types] +version = "0.3.0" + +[dependencies.libc] +version = "0.2" + +[features] +default = [] +elcapitan = [] +highsierra = [] diff --git a/third_party/cargo/vendor/core-foundation-sys-0.6.2/LICENSE-APACHE b/third_party/cargo/vendor/core-graphics-0.19.2/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/core-foundation-sys-0.6.2/LICENSE-APACHE rename to third_party/cargo/vendor/core-graphics-0.19.2/LICENSE-APACHE diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/LICENSE-MIT b/third_party/cargo/vendor/core-graphics-0.19.2/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/LICENSE-MIT rename to third_party/cargo/vendor/core-graphics-0.19.2/LICENSE-MIT diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/README.md b/third_party/cargo/vendor/core-graphics-0.19.2/README.md similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/README.md rename to third_party/cargo/vendor/core-graphics-0.19.2/README.md diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/base.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/base.rs new file mode 100644 index 0000000..bb27396 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/base.rs @@ -0,0 +1,59 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this file defines CGFloat, as well as stubbed data types. + +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +use libc; + +#[cfg(any(target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64"))] +pub type boolean_t = libc::c_int; +#[cfg(target_arch = "x86_64")] +pub type boolean_t = libc::c_uint; + +#[cfg(target_pointer_width = "64")] +pub type CGFloat = libc::c_double; +#[cfg(not(target_pointer_width = "64"))] +pub type CGFloat = libc::c_float; + +pub type CGError = i32; + +pub const kCGImageAlphaNone: u32 = 0; +pub const kCGImageAlphaPremultipliedLast: u32 = 1; +pub const kCGImageAlphaPremultipliedFirst: u32 = 2; +pub const kCGImageAlphaLast: u32 = 3; +pub const kCGImageAlphaFirst: u32 = 4; +pub const kCGImageAlphaNoneSkipLast: u32 = 5; +pub const kCGImageAlphaNoneSkipFirst: u32 = 6; + +pub const kCGBitmapByteOrderDefault: u32 = 0 << 12; +pub const kCGBitmapByteOrder16Little: u32 = 1 << 12; +pub const kCGBitmapByteOrder32Little: u32 = 2 << 12; +pub const kCGBitmapByteOrder16Big: u32 = 3 << 12; +pub const kCGBitmapByteOrder32Big: u32 = 4 << 12; + +pub const kCGRenderingIntentDefault: u32 = 0; +pub const kCGRenderingIntentAbsoluteColorimetric: u32 = 1; +pub const kCGRenderingIntentRelativeColorimetric: u32 = 2; +pub const kCGRenderingIntentPerceptual: u32 = 3; +pub const kCGRenderingIntentSaturation: u32 = 4; + +#[cfg(target_endian = "big")] +pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Big; +#[cfg(target_endian = "big")] +pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Big; + +#[cfg(target_endian = "little")] +pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Little; +#[cfg(target_endian = "little")] +pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Little; diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/color.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/color.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/color.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/color.rs diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/color_space.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/color_space.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/color_space.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/color_space.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/context.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/context.rs new file mode 100644 index 0000000..4efc0f7 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/context.rs @@ -0,0 +1,775 @@ +// Copyright 2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::CGFloat; +use color_space::CGColorSpace; +use core_foundation::base::{CFTypeID, TCFType}; +use font::{CGFont, CGGlyph}; +use geometry::{CGPoint, CGSize}; +use gradient::{CGGradient, CGGradientDrawingOptions}; +use color::CGColor; +use path::CGPathRef; +use libc::{c_int, size_t}; +use std::os::raw::c_void; + +use std::cmp; +use std::ptr; +use std::slice; +use geometry::{CGAffineTransform, CGRect}; +use image::CGImage; +use foreign_types::{ForeignType, ForeignTypeRef}; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGBlendMode { + Normal = 0, + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + SoftLight, + HardLight, + Difference, + Exclusion, + Hue, + Saturation, + Color, + Luminosity, + // 10.5 and up: + Clear, + Copy, + SourceIn, + SourceOut, + SourceAtop, + DestinationOver, + DestinationIn, + DestinationOut, + DestinationAtop, + Xor, + PlusDarker, + PlusLighter, +} + +#[repr(C)] +pub enum CGTextDrawingMode { + CGTextFill, + CGTextStroke, + CGTextFillStroke, + CGTextInvisible, + CGTextFillClip, + CGTextStrokeClip, + CGTextFillStrokeClip, + CGTextClip +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGLineCap { + CGLineCapButt, + CGLineCapRound, + CGLineCapSquare, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGLineJoin { + CGLineJoinMiter, + CGLineJoinRound, + CGLineJoinBevel, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGPathDrawingMode { + CGPathFill, + CGPathEOFill, + CGPathStroke, + CGPathFillStroke, + CGPathEOFillStroke, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGInterpolationQuality { + CGInterpolationQualityDefault, + CGInterpolationQualityNone, + CGInterpolationQualityLow, + CGInterpolationQualityMedium, + CGInterpolationQualityHigh, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGContext; + fn drop = |cs| CGContextRelease(cs); + fn clone = |p| CGContextRetain(p); + pub struct CGContext; + pub struct CGContextRef; +} + +impl CGContext { + pub fn type_id() -> CFTypeID { + unsafe { + CGContextGetTypeID() + } + } + + /// Creates a `CGContext` instance from an existing [`CGContextRef`] pointer. + /// + /// This funtion will internally call [`CGRetain`] and hence there is no need to call it explicitly. + /// + /// This function is particularly useful for cases when the context is not instantiated/managed + /// by the caller, but it's retrieve via other means (e.g., by calling the method [`NSGraphicsContext::CGContext`] + /// in a cocoa application). + /// + /// [`CGContextRef`]: https://developer.apple.com/documentation/coregraphics/cgcontextref + /// [`CGRetain`]: https://developer.apple.com/documentation/coregraphics/1586506-cgcontextretain + /// [`NSGraphicsContext::CGContext`]: https://developer.apple.com/documentation/appkit/nsgraphicscontext/1535352-currentcontext + pub unsafe fn from_existing_context_ptr(ctx: *mut ::sys::CGContext) -> CGContext { + CGContextRetain(ctx); + Self::from_ptr(ctx) + } + + pub fn create_bitmap_context(data: Option<*mut c_void>, + width: size_t, + height: size_t, + bits_per_component: size_t, + bytes_per_row: size_t, + space: &CGColorSpace, + bitmap_info: u32) + -> CGContext { + unsafe { + let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()), + width, + height, + bits_per_component, + bytes_per_row, + space.as_ptr(), + bitmap_info); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn data(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut( + CGBitmapContextGetData(self.as_ptr()) as *mut u8, + (self.height() * self.bytes_per_row()) as usize) + } + } +} + +impl CGContextRef { + pub fn flush(&self) { + unsafe { + CGContextFlush(self.as_ptr()) + } + } + + pub fn width(&self) -> size_t { + unsafe { + CGBitmapContextGetWidth(self.as_ptr()) + } + } + + pub fn height(&self) -> size_t { + unsafe { + CGBitmapContextGetHeight(self.as_ptr()) + } + } + + pub fn bytes_per_row(&self) -> size_t { + unsafe { + CGBitmapContextGetBytesPerRow(self.as_ptr()) + } + } + + pub fn clip_bounding_box(&self) -> CGRect { + unsafe { + CGContextGetClipBoundingBox(self.as_ptr()) + } + } + + pub fn set_fill_color(&self, color: &CGColor) { + unsafe { + CGContextSetFillColorWithColor(self.as_ptr(), color.as_concrete_TypeRef()); + } + } + + pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetRGBFillColor(self.as_ptr(), red, green, blue, alpha) + } + } + + pub fn set_rgb_stroke_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetRGBStrokeColor(self.as_ptr(), red, green, blue, alpha) + } + } + + pub fn set_gray_fill_color(&self, gray: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetGrayFillColor(self.as_ptr(), gray, alpha) + } + } + + pub fn set_blend_mode(&self, blend_mode: CGBlendMode) { + unsafe { + CGContextSetBlendMode(self.as_ptr(), blend_mode) + } + } + + pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) { + unsafe { + CGContextSetAllowsFontSmoothing(self.as_ptr(), allows_font_smoothing) + } + } + + pub fn set_font_smoothing_style(&self, style: i32) { + unsafe { + CGContextSetFontSmoothingStyle(self.as_ptr(), style as _); + } + } + + pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) { + unsafe { + CGContextSetShouldSmoothFonts(self.as_ptr(), should_smooth_fonts) + } + } + + pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) { + unsafe { + CGContextSetAllowsAntialiasing(self.as_ptr(), allows_antialiasing) + } + } + + pub fn set_should_antialias(&self, should_antialias: bool) { + unsafe { + CGContextSetShouldAntialias(self.as_ptr(), should_antialias) + } + } + + pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) { + unsafe { + CGContextSetAllowsFontSubpixelQuantization(self.as_ptr(), allows_font_subpixel_quantization) + } + } + + pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) { + unsafe { + CGContextSetShouldSubpixelQuantizeFonts(self.as_ptr(), should_subpixel_quantize_fonts) + } + } + + pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) { + unsafe { + CGContextSetAllowsFontSubpixelPositioning(self.as_ptr(), allows_font_subpixel_positioning) + } + } + + pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) { + unsafe { + CGContextSetShouldSubpixelPositionFonts(self.as_ptr(), should_subpixel_position_fonts) + } + } + + pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) { + unsafe { + CGContextSetTextDrawingMode(self.as_ptr(), mode) + } + } + + pub fn set_line_cap(&self, cap: CGLineCap) { + unsafe { + CGContextSetLineCap(self.as_ptr(), cap) + } + } + + pub fn set_line_dash(&self, phase: CGFloat, lengths: &[CGFloat]) { + unsafe { + CGContextSetLineDash(self.as_ptr(), phase, lengths.as_ptr(), lengths.len()) + } + } + + pub fn set_line_join(&self, join: CGLineJoin) { + unsafe { + CGContextSetLineJoin(self.as_ptr(), join) + } + } + + pub fn set_line_width(&self, width: CGFloat) { + unsafe { + CGContextSetLineWidth(self.as_ptr(), width) + } + } + + pub fn set_miter_limit(&self, limit: CGFloat) { + unsafe { + CGContextSetMiterLimit(self.as_ptr(), limit) + } + } + + pub fn add_path(&self, path: &CGPathRef) { + unsafe { + CGContextAddPath(self.as_ptr(), path.as_ptr()); + } + } + + pub fn add_curve_to_point(&self, + cp1x: CGFloat, + cp1y: CGFloat, + cp2x: CGFloat, + cp2y: CGFloat, + x: CGFloat, + y: CGFloat) { + unsafe { + CGContextAddCurveToPoint(self.as_ptr(), + cp1x, cp1y, + cp2x, cp2y, + x, y); + } + } + + pub fn add_quad_curve_to_point(&self, + cpx: CGFloat, + cpy: CGFloat, + x: CGFloat, + y: CGFloat) { + unsafe { + CGContextAddQuadCurveToPoint(self.as_ptr(), + cpx, cpy, + x, y); + } + } + + pub fn add_line_to_point(&self, x: CGFloat, y: CGFloat) { + unsafe { + CGContextAddLineToPoint(self.as_ptr(), x, y); + } + } + + pub fn begin_path(&self) { + unsafe { + CGContextBeginPath(self.as_ptr()); + } + } + + pub fn close_path(&self) { + unsafe { + CGContextClosePath(self.as_ptr()); + } + } + + pub fn move_to_point(&self, x: CGFloat, y: CGFloat) { + unsafe { + CGContextMoveToPoint(self.as_ptr(), x, y); + } + } + + pub fn clip(&self) { + unsafe { + CGContextClip(self.as_ptr()); + } + } + + pub fn eo_clip(&self) { + unsafe { + CGContextEOClip(self.as_ptr()); + } + } + + pub fn draw_path(&self, mode: CGPathDrawingMode) { + unsafe { + CGContextDrawPath(self.as_ptr(), mode); + } + } + + pub fn fill_path(&self) { + unsafe { + CGContextFillPath(self.as_ptr()); + } + } + + pub fn eo_fill_path(&self) { + unsafe { + CGContextEOFillPath(self.as_ptr()); + } + } + + pub fn stroke_path(&self) { + unsafe { + CGContextStrokePath(self.as_ptr()); + } + } + + pub fn fill_rect(&self, rect: CGRect) { + unsafe { + CGContextFillRect(self.as_ptr(), rect) + } + } + + pub fn fill_rects(&self, rects: &[CGRect]) { + unsafe { + CGContextFillRects(self.as_ptr(), rects.as_ptr(), rects.len()) + } + } + + pub fn clear_rect(&self, rect: CGRect) { + unsafe { + CGContextClearRect(self.as_ptr(), rect) + } + } + + pub fn stroke_rect(&self, rect: CGRect) { + unsafe { + CGContextStrokeRect(self.as_ptr(), rect) + } + } + + pub fn stroke_rect_with_width(&self, rect: CGRect, width: CGFloat) { + unsafe { + CGContextStrokeRectWithWidth(self.as_ptr(), rect, width) + } + } + + pub fn clip_to_rect(&self, rect: CGRect) { + unsafe { + CGContextClipToRect(self.as_ptr(), rect) + } + } + + pub fn clip_to_rects(&self, rects: &[CGRect]) { + unsafe { + CGContextClipToRects(self.as_ptr(), rects.as_ptr(), rects.len()) + } + } + + pub fn clip_to_mask(&self, rect: CGRect, image: &CGImage) { + unsafe { + CGContextClipToMask(self.as_ptr(), rect, image.as_ptr()) + } + } + + pub fn replace_path_with_stroked_path(&self) { + unsafe { + CGContextReplacePathWithStrokedPath(self.as_ptr()) + } + } + + pub fn fill_ellipse_in_rect(&self, rect: CGRect) { + unsafe { + CGContextFillEllipseInRect(self.as_ptr(), rect) + } + } + + pub fn stroke_ellipse_in_rect(&self, rect: CGRect) { + unsafe { + CGContextStrokeEllipseInRect(self.as_ptr(), rect) + } + } + + pub fn stroke_line_segments(&self, points: &[CGPoint]) { + unsafe { + CGContextStrokeLineSegments(self.as_ptr(), points.as_ptr(), points.len()) + } + } + + pub fn set_interpolation_quality(&self, quality: CGInterpolationQuality) { + unsafe { + CGContextSetInterpolationQuality(self.as_ptr(), quality); + } + } + + pub fn get_interpolation_quality(&self) -> CGInterpolationQuality { + unsafe { + CGContextGetInterpolationQuality(self.as_ptr()) + + } + } + + pub fn draw_image(&self, rect: CGRect, image: &CGImage) { + unsafe { + CGContextDrawImage(self.as_ptr(), rect, image.as_ptr()); + } + } + + pub fn create_image(&self) -> Option { + let image = unsafe { CGBitmapContextCreateImage(self.as_ptr()) }; + if !image.is_null() { + Some(unsafe { CGImage::from_ptr(image) }) + } else { + None + } + } + + pub fn set_font(&self, font: &CGFont) { + unsafe { + CGContextSetFont(self.as_ptr(), font.as_ptr()) + } + } + + pub fn set_font_size(&self, size: CGFloat) { + unsafe { + CGContextSetFontSize(self.as_ptr(), size) + } + } + + pub fn set_text_matrix(&self, t: &CGAffineTransform) { + unsafe { + CGContextSetTextMatrix(self.as_ptr(), *t) + } + } + + pub fn set_text_position(&self, x: CGFloat, y: CGFloat) { + unsafe { + CGContextSetTextPosition(self.as_ptr(), x, y) + } + } + + pub fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) { + unsafe { + let count = cmp::min(glyphs.len(), positions.len()); + CGContextShowGlyphsAtPositions(self.as_ptr(), + glyphs.as_ptr(), + positions.as_ptr(), + count) + } + } + + pub fn save(&self) { + unsafe { + CGContextSaveGState(self.as_ptr()); + } + } + + pub fn restore(&self) { + unsafe { + CGContextRestoreGState(self.as_ptr()); + } + } + + pub fn translate(&self, tx: CGFloat, ty: CGFloat) { + unsafe { + CGContextTranslateCTM(self.as_ptr(), tx, ty); + } + } + + pub fn scale(&self, sx: CGFloat, sy: CGFloat) { + unsafe { + CGContextScaleCTM(self.as_ptr(), sx, sy); + } + } + + pub fn rotate(&self, angle: CGFloat) { + unsafe { + CGContextRotateCTM(self.as_ptr(), angle); + } + } + + pub fn get_ctm(&self) -> CGAffineTransform { + unsafe { + CGContextGetCTM(self.as_ptr()) + } + } + + pub fn concat_ctm(&self, transform: CGAffineTransform) { + unsafe { + CGContextConcatCTM(self.as_ptr(), transform) + } + } + + pub fn draw_linear_gradient(&self, gradient: &CGGradient, start_point: CGPoint, end_point: CGPoint, options: CGGradientDrawingOptions) { + unsafe { + CGContextDrawLinearGradient(self.as_ptr(), gradient.as_ptr(), start_point, end_point, options); + } + } + + pub fn draw_radial_gradient(&self, gradient: &CGGradient, start_center: CGPoint, start_radius: CGFloat, end_center: CGPoint, end_radius: CGFloat, options: CGGradientDrawingOptions) { + unsafe { + CGContextDrawRadialGradient(self.as_ptr(), gradient.as_ptr(), start_center, start_radius, end_center, end_radius, options); + } + } + + pub fn set_shadow(&self, offset: CGSize, blur: CGFloat) { + unsafe { + CGContextSetShadow(self.as_ptr(), offset, blur); + } + } + + pub fn set_shadow_with_color(&self, offset: CGSize, blur: CGFloat, color: &CGColor) { + unsafe { + CGContextSetShadowWithColor(self.as_ptr(), offset, blur, color.as_concrete_TypeRef()); + } + } +} + +#[test] +fn create_bitmap_context_test() { + use geometry::*; + + let cs = CGColorSpace::create_device_rgb(); + let ctx = CGContext::create_bitmap_context(None, + 16, 8, + 8, 0, + &cs, + ::base::kCGImageAlphaPremultipliedLast); + ctx.set_rgb_fill_color(1.,0.,1.,1.); + ctx.set_miter_limit(4.); + ctx.fill_rect(CGRect::new(&CGPoint::new(0.,0.), &CGSize::new(8.,8.))); + let img = ctx.create_image().unwrap(); + assert_eq!(16, img.width()); + assert_eq!(8, img.height()); + assert_eq!(8, img.bits_per_component()); + assert_eq!(32, img.bits_per_pixel()); + let data = img.data(); + assert_eq!(255, data.bytes()[0]); + assert_eq!(0, data.bytes()[1]); + assert_eq!(255, data.bytes()[2]); + assert_eq!(255, data.bytes()[3]); +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGContextRetain(c: ::sys::CGContextRef) -> ::sys::CGContextRef; + fn CGContextRelease(c: ::sys::CGContextRef); + + fn CGBitmapContextCreate(data: *mut c_void, + width: size_t, + height: size_t, + bitsPerComponent: size_t, + bytesPerRow: size_t, + space: ::sys::CGColorSpaceRef, + bitmapInfo: u32) + -> ::sys::CGContextRef; + fn CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void; + fn CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef; + fn CGContextGetTypeID() -> CFTypeID; + fn CGContextGetClipBoundingBox(c: ::sys::CGContextRef) -> CGRect; + fn CGContextFlush(c: ::sys::CGContextRef); + fn CGContextSetBlendMode(c: ::sys::CGContextRef, blendMode: CGBlendMode); + fn CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool); + fn CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool); + fn CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int); + fn CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool); + fn CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool); + fn CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef, + allowsFontSubpixelQuantization: bool); + fn CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef, + shouldSubpixelQuantizeFonts: bool); + fn CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef, + allowsFontSubpixelPositioning: bool); + fn CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef, + shouldSubpixelPositionFonts: bool); + fn CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode); + fn CGContextSetFillColorWithColor(c: ::sys::CGContextRef, color: ::sys::CGColorRef); + fn CGContextSetLineCap(c: ::sys::CGContextRef, cap: CGLineCap); + fn CGContextSetLineDash(c: ::sys::CGContextRef, phase: CGFloat, lengths: *const CGFloat, count: size_t); + fn CGContextSetLineJoin(c: ::sys::CGContextRef, join: CGLineJoin); + fn CGContextSetLineWidth(c: ::sys::CGContextRef, width: CGFloat); + fn CGContextSetMiterLimit(c: ::sys::CGContextRef, limit: CGFloat); + + fn CGContextAddPath(c: ::sys::CGContextRef, path: ::sys::CGPathRef); + fn CGContextAddCurveToPoint(c: ::sys::CGContextRef, + cp1x: CGFloat, + cp1y: CGFloat, + cp2x: CGFloat, + cp2y: CGFloat, + x: CGFloat, + y: CGFloat); + fn CGContextAddQuadCurveToPoint(c: ::sys::CGContextRef, + cpx: CGFloat, + cpy: CGFloat, + x: CGFloat, + y: CGFloat); + fn CGContextAddLineToPoint(c: ::sys::CGContextRef, + x: CGFloat, + y: CGFloat); + fn CGContextBeginPath(c: ::sys::CGContextRef); + fn CGContextClosePath(c: ::sys::CGContextRef); + fn CGContextMoveToPoint(c: ::sys::CGContextRef, + x: CGFloat, + y: CGFloat); + fn CGContextDrawPath(c: ::sys::CGContextRef, mode: CGPathDrawingMode); + fn CGContextFillPath(c: ::sys::CGContextRef); + fn CGContextEOFillPath(c: ::sys::CGContextRef); + fn CGContextClip(c: ::sys::CGContextRef); + fn CGContextEOClip(c: ::sys::CGContextRef); + fn CGContextStrokePath(c: ::sys::CGContextRef); + fn CGContextSetRGBFillColor(context: ::sys::CGContextRef, + red: CGFloat, + green: CGFloat, + blue: CGFloat, + alpha: CGFloat); + fn CGContextSetRGBStrokeColor(context: ::sys::CGContextRef, + red: CGFloat, + green: CGFloat, + blue: CGFloat, + alpha: CGFloat); + fn CGContextSetGrayFillColor(context: ::sys::CGContextRef, gray: CGFloat, alpha: CGFloat); + fn CGContextClearRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextFillRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextFillRects(context: ::sys::CGContextRef, + rects: *const CGRect, + count: size_t); + fn CGContextStrokeRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextStrokeRectWithWidth(context: ::sys::CGContextRef, + rect: CGRect, + width: CGFloat); + fn CGContextClipToRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextClipToRects(context: ::sys::CGContextRef, + rects: *const CGRect, + count: size_t); + fn CGContextClipToMask(ctx: ::sys::CGContextRef, rect: CGRect, mask: ::sys::CGImageRef); + fn CGContextReplacePathWithStrokedPath(context: ::sys::CGContextRef); + fn CGContextFillEllipseInRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextStrokeEllipseInRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextStrokeLineSegments(context: ::sys::CGContextRef, + points: *const CGPoint, + count: size_t); + fn CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef); + fn CGContextSetInterpolationQuality(c: ::sys::CGContextRef, quality: CGInterpolationQuality); + fn CGContextGetInterpolationQuality(c: ::sys::CGContextRef) -> CGInterpolationQuality; + fn CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef); + fn CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat); + fn CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform); + fn CGContextSetTextPosition(c: ::sys::CGContextRef, x: CGFloat, y: CGFloat); + fn CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef, + glyphs: *const CGGlyph, + positions: *const CGPoint, + count: size_t); + + fn CGContextSaveGState(c: ::sys::CGContextRef); + fn CGContextRestoreGState(c: ::sys::CGContextRef); + fn CGContextTranslateCTM(c: ::sys::CGContextRef, tx: CGFloat, ty: CGFloat); + fn CGContextScaleCTM(c: ::sys::CGContextRef, sx: CGFloat, sy: CGFloat); + fn CGContextRotateCTM(c: ::sys::CGContextRef, angle: CGFloat); + fn CGContextGetCTM(c: ::sys::CGContextRef) -> CGAffineTransform; + fn CGContextConcatCTM(c: ::sys::CGContextRef, transform: CGAffineTransform); + + fn CGContextDrawLinearGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startPoint: CGPoint, endPoint: CGPoint, options: CGGradientDrawingOptions); + fn CGContextDrawRadialGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startCenter: CGPoint, startRadius: CGFloat, endCenter:CGPoint, endRadius:CGFloat, options: CGGradientDrawingOptions); + + fn CGContextSetShadow(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat); + fn CGContextSetShadowWithColor(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat, color: ::sys::CGColorRef); +} + diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/data_provider.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/data_provider.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/data_provider.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/data_provider.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/display.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/display.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/display.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/display.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/event.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/event.rs new file mode 100644 index 0000000..f28e293 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/event.rs @@ -0,0 +1,669 @@ +#![allow(non_upper_case_globals)] + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use geometry::CGPoint; +use event_source::CGEventSource; + +use libc; + +use foreign_types::ForeignType; + +pub type CGEventField = u32; +pub type CGKeyCode = u16; +pub type CGScrollEventUnit = u32; + +bitflags! { + /// Flags for events + /// + /// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) + #[repr(C)] + pub struct CGEventFlags: u64 { + const CGEventFlagNull = 0; + + // Device-independent modifier key bits. + const CGEventFlagAlphaShift = 0x00010000; + const CGEventFlagShift = 0x00020000; + const CGEventFlagControl = 0x00040000; + const CGEventFlagAlternate = 0x00080000; + const CGEventFlagCommand = 0x00100000; + + // Special key identifiers. + const CGEventFlagHelp = 0x00400000; + const CGEventFlagSecondaryFn = 0x00800000; + + // Identifies key events from numeric keypad area on extended keyboards. + const CGEventFlagNumericPad = 0x00200000; + + // Indicates if mouse/pen movement events are not being coalesced + const CGEventFlagNonCoalesced = 0x00000100; + } +} + +/// Key codes for keys that are independent of keyboard layout. +/// +/// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h) +#[repr(C)] +pub struct KeyCode; +impl KeyCode { + pub const RETURN: CGKeyCode = 0x24; + pub const TAB: CGKeyCode = 0x30; + pub const SPACE: CGKeyCode = 0x31; + pub const DELETE: CGKeyCode = 0x33; + pub const ESCAPE: CGKeyCode = 0x35; + pub const COMMAND: CGKeyCode = 0x37; + pub const SHIFT: CGKeyCode = 0x38; + pub const CAPS_LOCK: CGKeyCode = 0x39; + pub const OPTION: CGKeyCode = 0x3A; + pub const CONTROL: CGKeyCode = 0x3B; + pub const RIGHT_COMMAND: CGKeyCode = 0x36; + pub const RIGHT_SHIFT: CGKeyCode = 0x3C; + pub const RIGHT_OPTION: CGKeyCode = 0x3D; + pub const RIGHT_CONTROL: CGKeyCode = 0x3E; + pub const FUNCTION: CGKeyCode = 0x3F; + pub const VOLUME_UP: CGKeyCode = 0x48; + pub const VOLUME_DOWN: CGKeyCode = 0x49; + pub const MUTE: CGKeyCode = 0x4A; + pub const F1: CGKeyCode = 0x7A; + pub const F2: CGKeyCode = 0x78; + pub const F3: CGKeyCode = 0x63; + pub const F4: CGKeyCode = 0x76; + pub const F5: CGKeyCode = 0x60; + pub const F6: CGKeyCode = 0x61; + pub const F7: CGKeyCode = 0x62; + pub const F8: CGKeyCode = 0x64; + pub const F9: CGKeyCode = 0x65; + pub const F10: CGKeyCode = 0x6D; + pub const F11: CGKeyCode = 0x67; + pub const F12: CGKeyCode = 0x6F; + pub const F13: CGKeyCode = 0x69; + pub const F14: CGKeyCode = 0x6B; + pub const F15: CGKeyCode = 0x71; + pub const F16: CGKeyCode = 0x6A; + pub const F17: CGKeyCode = 0x40; + pub const F18: CGKeyCode = 0x4F; + pub const F19: CGKeyCode = 0x50; + pub const F20: CGKeyCode = 0x5A; + pub const HELP: CGKeyCode = 0x72; + pub const HOME: CGKeyCode = 0x73; + pub const PAGE_UP: CGKeyCode = 0x74; + pub const FORWARD_DELETE: CGKeyCode = 0x75; + pub const END: CGKeyCode = 0x77; + pub const PAGE_DOWN: CGKeyCode = 0x79; + pub const LEFT_ARROW: CGKeyCode = 0x7B; + pub const RIGHT_ARROW: CGKeyCode = 0x7C; + pub const DOWN_ARROW: CGKeyCode = 0x7D; + pub const UP_ARROW: CGKeyCode = 0x7E; +} + +#[repr(C)] +pub struct ScrollEventUnit {} +impl ScrollEventUnit { + pub const PIXEL: CGScrollEventUnit = 0; + pub const LINE: CGScrollEventUnit = 1; +} + +/// Constants that specify the different types of input events. +/// +/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) +#[repr(u32)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventType { + Null = 0, + + // Mouse events. + LeftMouseDown = 1, + LeftMouseUp = 2, + RightMouseDown = 3, + RightMouseUp = 4, + MouseMoved = 5, + LeftMouseDragged = 6, + RightMouseDragged = 7, + + // Keyboard events. + KeyDown = 10, + KeyUp = 11, + FlagsChanged = 12, + + // Specialized control devices. + ScrollWheel = 22, + TabletPointer = 23, + TabletProximity = 24, + OtherMouseDown = 25, + OtherMouseUp = 26, + OtherMouseDragged = 27, + + // Out of band event types. These are delivered to the event tap callback + // to notify it of unusual conditions that disable the event tap. + TapDisabledByTimeout = 0xFFFFFFFE, + TapDisabledByUserInput = 0xFFFFFFFF, +} + +/// Constants used as keys to access specialized fields in low-level events. +/// +/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield) +pub struct EventField; +impl EventField { + /// Key to access an integer field that contains the mouse button event + /// number. Matching mouse-down and mouse-up events will have the same + /// event number. + pub const MOUSE_EVENT_NUMBER: CGEventField = 0; + + /// Key to access an integer field that contains the mouse button click + /// state. A click state of 1 represents a single click. A click state of + /// 2 represents a double-click. A click state of 3 represents a + /// triple-click. + pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1; + + /// Key to access a double field that contains the mouse button pressure. + /// The pressure value may range from 0 to 1, with 0 representing the + /// mouse being up. This value is commonly set by tablet pens mimicking a + /// mouse. + pub const MOUSE_EVENT_PRESSURE: CGEventField = 2; + + /// Key to access an integer field that contains the mouse button number. + pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3; + + /// Key to access an integer field that contains the horizontal mouse + /// delta since the last mouse movement event. + pub const MOUSE_EVENT_DELTA_X: CGEventField = 4; + + /// Key to access an integer field that contains the vertical mouse delta + /// since the last mouse movement event. + pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5; + + /// Key to access an integer field. The value is non-zero if the event + /// should be ignored by the Inkwell subsystem. + pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6; + + /// Key to access an integer field that encodes the mouse event subtype as + /// a `kCFNumberIntType'. + pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7; + + /// Key to access an integer field, non-zero when this is an autorepeat of + /// a key-down, and zero otherwise. + pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8; + + /// Key to access an integer field that contains the virtual keycode of the + /// key-down or key-up event. + pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9; + + /// Key to access an integer field that contains the keyboard type + /// identifier. + pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10; + + /// Key to access an integer field that contains scrolling data. This field + /// typically contains the change in vertical position since the last + /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse + /// scroller. + pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11; + + /// Key to access an integer field that contains scrolling data. This field + /// typically contains the change in horizontal position since the last + /// scrolling event from a Mighty Mouse scroller. + pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12; + + /// Key to access a field that contains scrolling data. The scrolling data + /// represents a line-based or pixel-based change in vertical position + /// since the last scrolling event from a Mighty Mouse scroller or a + /// single-wheel mouse scroller. The scrolling data uses a fixed-point + /// 16.16 signed integer format. If this key is passed to + /// `CGEventGetDoubleValueField', the fixed-point value is converted to a + /// double value. + pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93; + + /// Key to access a field that contains scrolling data. The scrolling data + /// represents a line-based or pixel-based change in horizontal position + /// since the last scrolling event from a Mighty Mouse scroller. The + /// scrolling data uses a fixed-point 16.16 signed integer format. If this + /// key is passed to `CGEventGetDoubleValueField', the fixed-point value is + /// converted to a double value. + pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94; + + /// Key to access an integer field that contains pixel-based scrolling + /// data. The scrolling data represents the change in vertical position + /// since the last scrolling event from a Mighty Mouse scroller or a + /// single-wheel mouse scroller. + pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96; + + /// Key to access an integer field that contains pixel-based scrolling + /// data. The scrolling data represents the change in horizontal position + /// since the last scrolling event from a Mighty Mouse scroller. + pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97; + + /// Key to access an integer field that indicates whether the event should + /// be ignored by the Inkwell subsystem. If the value is non-zero, the + /// event should be ignored. + pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14; + + /// Key to access an integer field that contains the absolute X coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_X: CGEventField = 15; + + /// Key to access an integer field that contains the absolute Y coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_Y: CGEventField = 16; + + /// Key to access an integer field that contains the absolute Z coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_Z: CGEventField = 17; + + /// Key to access an integer field that contains the tablet button state. + /// Bit 0 is the first button, and a set bit represents a closed or pressed + /// button. Up to 16 buttons are supported. + pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18; + + /// Key to access a double field that contains the tablet pen pressure. A + /// value of 0.0 represents no pressure, and 1.0 represents maximum + /// pressure. + pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19; + + /// Key to access a double field that contains the horizontal tablet pen + /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. + pub const TABLET_EVENT_TILT_X: CGEventField = 20; + + /// Key to access a double field that contains the vertical tablet pen + /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. + pub const TABLET_EVENT_TILT_Y: CGEventField = 21; + + /// Key to access a double field that contains the tablet pen rotation. + pub const TABLET_EVENT_ROTATION: CGEventField = 22; + + /// Key to access a double field that contains the tangential pressure on + /// the device. A value of 0.0 represents no pressure, and 1.0 represents + /// maximum pressure. + pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23; + + /// Key to access an integer field that contains the system-assigned unique + /// device ID. + pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_1: CGEventField = 25; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_2: CGEventField = 26; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_3: CGEventField = 27; + + /// Key to access an integer field that contains the vendor-defined ID, + /// typically the USB vendor ID. + pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28; + + /// Key to access an integer field that contains the vendor-defined tablet + /// ID, typically the USB product ID. + pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29; + + /// Key to access an integer field that contains the vendor-defined ID of + /// the pointing device. + pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30; + + /// Key to access an integer field that contains the system-assigned + /// device ID. + pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31; + + /// Key to access an integer field that contains the system-assigned + /// unique tablet ID. + pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32; + + /// Key to access an integer field that contains the vendor-assigned + /// pointer type. + pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33; + + /// Key to access an integer field that contains the vendor-defined + /// pointer serial number. + pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34; + + /// Key to access an integer field that contains the vendor-defined unique + /// ID. + pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35; + + /// Key to access an integer field that contains the device capabilities + /// mask. + pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36; + + /// Key to access an integer field that contains the pointer type. + pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37; + + /// Key to access an integer field that indicates whether the pen is in + /// proximity to the tablet. The value is non-zero if the pen is in + /// proximity to the tablet and zero when leaving the tablet. + pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38; + + /// Key to access a field that contains the event target process serial + /// number. The value is a 64-bit value. + pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39; + + /// Key to access a field that contains the event target Unix process ID. + pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40; + + /// Key to access a field that contains the event source Unix process ID. + pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41; + + /// Key to access a field that contains the event source user-supplied + /// data, up to 64 bits. + pub const EVENT_SOURCE_USER_DATA: CGEventField = 42; + + /// Key to access a field that contains the event source Unix effective UID. + pub const EVENT_SOURCE_USER_ID: CGEventField = 43; + + /// Key to access a field that contains the event source Unix effective + /// GID. + pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44; + + /// Key to access a field that contains the event source state ID used to + /// create this event. + pub const EVENT_SOURCE_STATE_ID: CGEventField = 45; + + /// Key to access an integer field that indicates whether a scrolling event + /// contains continuous, pixel-based scrolling data. The value is non-zero + /// when the scrolling data is pixel-based and zero when the scrolling data + /// is line-based. + pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88; + + /// Added in 10.5; made public in 10.7. + pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91; + pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92; +} + +// Constants that specify buttons on a one, two, or three-button mouse. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGMouseButton { + Left, + Right, + Center, +} + +/// Possible tapping points for events. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventTapLocation { + HID, + Session, + AnnotatedSession, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGEvent; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGEvent; + pub struct CGEventRef; +} + +impl CGEvent { + pub fn type_id() -> CFTypeID { + unsafe { + CGEventGetTypeID() + } + } + + pub fn new(source: CGEventSource) -> Result { + unsafe { + let event_ref = CGEventCreate(source.as_ptr()); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn new_keyboard_event( + source: CGEventSource, + keycode: CGKeyCode, + keydown: bool + ) -> Result { + unsafe { + let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn new_mouse_event( + source: CGEventSource, + mouse_type: CGEventType, + mouse_cursor_position: CGPoint, + mouse_button: CGMouseButton + ) -> Result { + unsafe { + let event_ref = CGEventCreateMouseEvent(source.as_ptr(), mouse_type, + mouse_cursor_position, mouse_button); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + #[cfg(feature = "highsierra")] + pub fn new_scroll_event( + source: CGEventSource, + units: CGScrollEventUnit, + wheel_count: u32, + wheel1: i32, + wheel2: i32, + wheel3: i32, + ) -> Result { + unsafe { + let event_ref = CGEventCreateScrollWheelEvent2( + source.as_ptr(), + units, + wheel_count, + wheel1, + wheel2, + wheel3, + ); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn post(&self, tap_location: CGEventTapLocation) { + unsafe { + CGEventPost(tap_location, self.as_ptr()); + } + } + + pub fn location(&self) -> CGPoint { + unsafe { + CGEventGetLocation(self.as_ptr()) + } + } + + #[cfg(feature = "elcapitan")] + pub fn post_to_pid(&self, pid: libc::pid_t) { + unsafe { + CGEventPostToPid(pid, self.as_ptr()); + } + } + + pub fn set_flags(&self, flags: CGEventFlags) { + unsafe { + CGEventSetFlags(self.as_ptr(), flags); + } + } + + pub fn get_flags(&self) -> CGEventFlags { + unsafe { + CGEventGetFlags(self.as_ptr()) + } + } + + pub fn set_type(&self, event_type: CGEventType) { + unsafe { + CGEventSetType(self.as_ptr(), event_type); + } + } + + pub fn get_type(&self) -> CGEventType { + unsafe { + CGEventGetType(self.as_ptr()) + } + } + + pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) { + let buflen = buf.len() as libc::c_ulong; + unsafe { + CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr()); + } + } + + pub fn set_string(&self, string: &str) { + let buf: Vec = string.encode_utf16().collect(); + self.set_string_from_utf16_unchecked(&buf); + } + + pub fn get_integer_value_field(&self, field: CGEventField) -> i64 { + unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) } + } + + pub fn set_integer_value_field(&self, field: CGEventField, value: i64) { + unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) } + } + + pub fn get_double_value_field(&self, field: CGEventField) -> f64 { + unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) } + } + + pub fn set_double_value_field(&self, field: CGEventField, value: f64) { + unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + /// Return the type identifier for the opaque type `CGEventRef'. + fn CGEventGetTypeID() -> CFTypeID; + + /// Return a new event using the event source `source'. If `source' is NULL, + /// the default source is used. + fn CGEventCreate(source: ::sys::CGEventSourceRef) -> ::sys::CGEventRef; + + /// Return a new keyboard event. + /// + /// The event source may be taken from another event, or may be NULL. Based + /// on the virtual key code values entered, the appropriate key down, key up, + /// or flags changed events are generated. + /// + /// All keystrokes needed to generate a character must be entered, including + /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z', + /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT + /// and 'z' key must be released: + fn CGEventCreateKeyboardEvent(source: ::sys::CGEventSourceRef, keycode: CGKeyCode, + keydown: bool) -> ::sys::CGEventRef; + + /// Return a new mouse event. + /// + /// The event source may be taken from another event, or may be NULL. + /// `mouseType' should be one of the mouse event types. `mouseCursorPosition' + /// should be the position of the mouse cursor in global coordinates. + /// `mouseButton' should be the button that's changing state; `mouseButton' + /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown', + /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'. + /// + /// The current implementation of the event system supports a maximum of + /// thirty-two buttons. Mouse button 0 is the primary button on the mouse. + /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is + /// the center button, and the remaining buttons are in USB device order. + fn CGEventCreateMouseEvent(source: ::sys::CGEventSourceRef, mouseType: CGEventType, + mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> ::sys::CGEventRef; + + /// A non-variadic variant version of CGEventCreateScrollWheelEvent. + /// + /// Returns a new Quartz scrolling event. + /// + /// This function allows you to create a scrolling event and customize the + /// event before posting it to the event system. + #[cfg(feature = "highsierra")] + fn CGEventCreateScrollWheelEvent2( + source: ::sys::CGEventSourceRef, + units: CGScrollEventUnit, + wheelCount: u32, + wheel1: i32, + wheel2: i32, + wheel3: i32, + ) -> ::sys::CGEventRef; + + /// Post an event into the event stream at a specified location. + /// + /// This function posts the specified event immediately before any event taps + /// instantiated for that location, and the event passes through any such + /// taps. + fn CGEventPost(tapLocation: CGEventTapLocation, event: ::sys::CGEventRef); + + #[cfg(feature = "elcapitan")] + /// Post an event to a specified process ID + fn CGEventPostToPid(pid: libc::pid_t, event: ::sys::CGEventRef); + + /// Set the event flags of an event. + fn CGEventSetFlags(event: ::sys::CGEventRef, flags: CGEventFlags); + + /// Return the event flags of an event. + fn CGEventGetFlags(event: ::sys::CGEventRef) -> CGEventFlags; + + /// Return the location of an event in global display coordinates. + /// CGPointZero is returned if event is not a valid ::sys::CGEventRef. + fn CGEventGetLocation(event: ::sys::CGEventRef) -> CGPoint; + + /// Set the event type of an event. + fn CGEventSetType(event: ::sys::CGEventRef, eventType: CGEventType); + + /// Return the event type of an event (left mouse down, for example). + fn CGEventGetType(event: ::sys::CGEventRef) -> CGEventType; + + /// Set the Unicode string associated with a keyboard event. + /// + /// By default, the system translates the virtual key code in a keyboard + /// event into a Unicode string based on the keyboard ID in the event + /// source. This function allows you to manually override this string. + /// Note that application frameworks may ignore the Unicode string in a + /// keyboard event and do their own translation based on the virtual + /// keycode and perceived event state. + fn CGEventKeyboardSetUnicodeString(event: ::sys::CGEventRef, + length: libc::c_ulong, + string: *const u16); + + /// Return the integer value of a field in an event. + fn CGEventGetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField) -> i64; + + /// Set the integer value of a field in an event. + /// + /// Before calling this function, the event type must be set using a typed + /// event creation function such as `CGEventCreateMouseEvent', or by + /// calling `CGEventSetType'. + /// + /// If you are creating a mouse event generated by a tablet, call this + /// function and specify the field `kCGMouseEventSubtype' with a value of + /// `kCGEventMouseSubtypeTabletPoint' or + /// `kCGEventMouseSubtypeTabletProximity' before setting other parameters. + fn CGEventSetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField, value: i64); + + /// Return the floating-point value of a field in an event. + /// + /// In cases where the field value is represented within the event by a fixed + /// point number or an integer, the result is scaled to the appropriate range + /// as part of creating the floating-point representation. + fn CGEventGetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField) -> f64; + + /// Set the floating-point value of a field in an event. + /// + /// Before calling this function, the event type must be set using a typed + /// event creation function such as `CGEventCreateMouseEvent', or by calling + /// `CGEventSetType'. + /// + /// In cases where the field’s value is represented within the event by a + /// fixed point number or integer, the value parameter is scaled as needed + /// and converted to the appropriate type. + fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64); +} diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/event_source.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/event_source.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/event_source.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/event_source.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/font.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/font.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/font.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/font.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/geometry.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/geometry.rs new file mode 100644 index 0000000..585d25f --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/geometry.rs @@ -0,0 +1,275 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::CGFloat; +use core_foundation::base::TCFType; +use core_foundation::dictionary::CFDictionary; + +pub const CG_ZERO_POINT: CGPoint = CGPoint { + x: 0.0, + y: 0.0, +}; + +pub const CG_ZERO_SIZE: CGSize = CGSize { + width: 0.0, + height: 0.0, +}; + +pub const CG_ZERO_RECT: CGRect = CGRect { + origin: CG_ZERO_POINT, + size: CG_ZERO_SIZE, +}; + +pub const CG_AFFINE_TRANSFORM_IDENTITY: CGAffineTransform = CGAffineTransform { + a: 1.0, b: 0.0, + c: 0.0, d: 1.0, + tx: 0.0, ty: 0.0, +}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct CGSize { + pub width: CGFloat, + pub height: CGFloat, +} + +impl CGSize { + #[inline] + pub fn new(width: CGFloat, height: CGFloat) -> CGSize { + CGSize { + width: width, + height: height, + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGSize { + unsafe { + ffi::CGSizeApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct CGPoint { + pub x: CGFloat, + pub y: CGFloat, +} + +impl CGPoint { + #[inline] + pub fn new(x: CGFloat, y: CGFloat) -> CGPoint { + CGPoint { + x: x, + y: y, + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGPoint { + unsafe { + ffi::CGPointApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGRect { + pub origin: CGPoint, + pub size: CGSize +} + +impl CGRect { + #[inline] + pub fn new(origin: &CGPoint, size: &CGSize) -> CGRect { + CGRect { + origin: *origin, + size: *size, + } + } + + #[inline] + pub fn inset(&self, size: &CGSize) -> CGRect { + unsafe { + ffi::CGRectInset(*self, size.width, size.height) + } + } + + #[inline] + pub fn from_dict_representation(dict: &CFDictionary) -> Option { + let mut rect = CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(0., 0.)); + let result = unsafe { + ffi::CGRectMakeWithDictionaryRepresentation(dict.as_concrete_TypeRef(), &mut rect) + }; + if result == 0 { + None + } else { + Some(rect) + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + unsafe { + // I use one, as it seems that `YES` is not available from this crate. + ffi::CGRectIsEmpty(*self) == 1 + } + } + + #[inline] + pub fn is_intersects(&self, other: &CGRect) -> bool { + unsafe { + // I use one, as it seems that `YES` is not available from this crate. + ffi::CGRectIntersectsRect(*self, *other) == 1 + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGRect { + unsafe { + ffi::CGRectApplyAffineTransform(*self, *t) + } + } +} + +impl PartialEq for CGRect { + #[inline] + fn eq(&self, other: &CGRect) -> bool { + unsafe { + ffi::CGRectEqualToRect(*self, *other) != 0 + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGAffineTransform { + pub a: CGFloat, + pub b: CGFloat, + pub c: CGFloat, + pub d: CGFloat, + pub tx: CGFloat, + pub ty: CGFloat, +} + +impl CGAffineTransform { + #[inline] + pub fn new( + a: CGFloat, + b: CGFloat, + c: CGFloat, + d: CGFloat, + tx: CGFloat, + ty: CGFloat, + ) -> CGAffineTransform { + CGAffineTransform { a, b, c, d, tx, ty } + } + + #[inline] + pub fn make_translation(tx: CGFloat, ty: CGFloat) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformMakeTranslation(tx, ty) + } + } + + #[inline] + pub fn make_rotation(angle: CGFloat) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformMakeRotation(angle) + } + } + + #[inline] + pub fn make_scale(sx: CGFloat, sy: CGFloat) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformMakeScale(sx, sy) + } + } + + #[inline] + pub fn translate(&self, tx: CGFloat, ty: CGFloat) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformTranslate(*self, tx, ty) + } + } + + #[inline] + pub fn rotate(&self, angle: CGFloat) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformRotate(*self, angle) + } + } + + #[inline] + pub fn scale(&self, sx: CGFloat, sy: CGFloat) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformScale(*self, sx, sy) + } + } + + #[inline] + pub fn invert(&self) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformInvert(*self) + } + } + + #[inline] + pub fn concat(&self, t: CGAffineTransform) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformConcat(*self, t) + } + } +} + +impl PartialEq for CGAffineTransform { + #[inline] + fn eq(&self, other: &CGAffineTransform) -> bool { + unsafe { + ffi::CGAffineTransformEqualToTransform(*self, *other) != 0 + } + } +} + +mod ffi { + use base::{CGFloat, boolean_t}; + use geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; + use core_foundation::dictionary::CFDictionaryRef; + + #[link(name = "CoreGraphics", kind = "framework")] + extern { + pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect; + pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef, + rect: *mut CGRect) -> boolean_t; + pub fn CGRectIsEmpty(rect: CGRect) -> boolean_t; + pub fn CGRectIntersectsRect(rect1: CGRect, rect2: CGRect) -> boolean_t; + pub fn CGRectEqualToRect(rect1: CGRect, rect2: CGRect) -> boolean_t; + + // Creating an Affine Transformation Matrix + pub fn CGAffineTransformMakeTranslation(tx: CGFloat, ty: CGFloat) -> CGAffineTransform; + pub fn CGAffineTransformMakeRotation(angle: CGFloat) -> CGAffineTransform; + pub fn CGAffineTransformMakeScale(sx: CGFloat, sy: CGFloat) -> CGAffineTransform; + + // Modifying Affine Transformations + pub fn CGAffineTransformTranslate(t: CGAffineTransform, tx: CGFloat, ty: CGFloat) -> CGAffineTransform; + pub fn CGAffineTransformRotate(t: CGAffineTransform, angle: CGFloat) -> CGAffineTransform; + pub fn CGAffineTransformScale(t: CGAffineTransform, sx: CGFloat, sy: CGFloat) -> CGAffineTransform; + pub fn CGAffineTransformInvert(t: CGAffineTransform) -> CGAffineTransform; + pub fn CGAffineTransformConcat(t1: CGAffineTransform, t2: CGAffineTransform) -> CGAffineTransform; + pub fn CGAffineTransformEqualToTransform(t1: CGAffineTransform, + t2: CGAffineTransform) -> boolean_t; + + pub fn CGPointApplyAffineTransform(point: CGPoint, t: CGAffineTransform) -> CGPoint; + pub fn CGRectApplyAffineTransform(rect: CGRect, t: CGAffineTransform) -> CGRect; + pub fn CGSizeApplyAffineTransform(size: CGSize, t: CGAffineTransform) -> CGSize; + } +} + diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/gradient.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/gradient.rs new file mode 100644 index 0000000..5c6cde8 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/gradient.rs @@ -0,0 +1,62 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use base::CGFloat; +use color::CGColor; +use color_space::CGColorSpace; + +use core_foundation::array::{ CFArray, CFArrayRef }; +use core_foundation::base::{CFRelease, CFRetain, TCFType}; +use foreign_types::ForeignType; + +use libc::size_t; + +bitflags! { + #[repr(C)] + pub struct CGGradientDrawingOptions: u32 { + const CGGradientDrawsBeforeStartLocation = (1 << 0); + const CGGradientDrawsAfterEndLocation = (1 << 1); + } +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGGradient; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGGradient; + pub struct CGGradientRef; +} + +impl CGGradient { + pub fn create_with_color_components(color_space: &CGColorSpace, components: &[CGFloat], locations: &[CGFloat], count: usize) -> CGGradient { + unsafe { + let result = CGGradientCreateWithColorComponents(color_space.as_ptr(), components.as_ptr(), locations.as_ptr(), count); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn create_with_colors(color_space: &CGColorSpace, colors: &CFArray, locations: &[CGFloat]) -> CGGradient { + unsafe { + let result = CGGradientCreateWithColors(color_space.as_ptr(), colors.as_concrete_TypeRef(), locations.as_ptr()); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGGradientCreateWithColorComponents(color_space: ::sys::CGColorSpaceRef, components: *const CGFloat, locations: *const CGFloat, count: size_t) -> ::sys::CGGradientRef; + fn CGGradientCreateWithColors(color_space: ::sys::CGColorSpaceRef, colors: CFArrayRef, locations: *const CGFloat) -> ::sys::CGGradientRef; +} + diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/image.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/image.rs new file mode 100644 index 0000000..f1b9509 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/image.rs @@ -0,0 +1,165 @@ +use std::ptr; + +use base::CGFloat; +use core_foundation::base::{CFRetain, CFTypeID}; +use core_foundation::data::CFData; +use color_space::CGColorSpace; +use data_provider::{CGDataProviderRef, CGDataProvider}; +use geometry::CGRect; +use libc::size_t; +use foreign_types::{ForeignType, ForeignTypeRef}; + +#[repr(C)] +pub enum CGImageAlphaInfo { + CGImageAlphaNone, /* For example, RGB. */ + CGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ + CGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ + CGImageAlphaLast, /* For example, non-premultiplied RGBA */ + CGImageAlphaFirst, /* For example, non-premultiplied ARGB */ + CGImageAlphaNoneSkipLast, /* For example, RBGX. */ + CGImageAlphaNoneSkipFirst, /* For example, XRBG. */ + CGImageAlphaOnly /* No color data, alpha data only */ +} + +#[repr(C)] +pub enum CGImageByteOrderInfo { + CGImageByteOrderMask = 0x7000, + CGImageByteOrder16Little = 1 << 12, + CGImageByteOrder32Little = 2 << 12, + CGImageByteOrder16Big = 3 << 12, + CGImageByteOrder32Big = 4 << 12 +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGImage; + fn drop = CGImageRelease; + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGImage; + pub struct CGImageRef; +} + +impl CGImage { + pub fn new(width: size_t, + height: size_t, + bits_per_component: size_t, + bits_per_pixel: size_t, + bytes_per_row: size_t, + colorspace: &CGColorSpace, + bitmap_info: u32, + provider: &CGDataProvider, + should_interpolate: bool, + rendering_intent: u32) + -> Self { + unsafe { + let result = CGImageCreate(width, + height, + bits_per_component, + bits_per_pixel, + bytes_per_row, + colorspace.as_ptr(), + bitmap_info, + provider.as_ptr(), + ptr::null_mut(), + should_interpolate, + rendering_intent); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn type_id() -> CFTypeID { + unsafe { + CGImageGetTypeID() + } + } +} + +impl CGImageRef { + pub fn width(&self) -> size_t { + unsafe { + CGImageGetWidth(self.as_ptr()) + } + } + + pub fn height(&self) -> size_t { + unsafe { + CGImageGetHeight(self.as_ptr()) + } + } + + pub fn bits_per_component(&self) -> size_t { + unsafe { + CGImageGetBitsPerComponent(self.as_ptr()) + } + } + + pub fn bits_per_pixel(&self) -> size_t { + unsafe { + CGImageGetBitsPerPixel(self.as_ptr()) + } + } + + pub fn bytes_per_row(&self) -> size_t { + unsafe { + CGImageGetBytesPerRow(self.as_ptr()) + } + } + + pub fn color_space(&self) -> CGColorSpace { + unsafe { + let cs = CGImageGetColorSpace(self.as_ptr()); + CFRetain(cs as *mut _); + CGColorSpace::from_ptr(cs) + } + } + + /// Returns the raw image bytes wrapped in `CFData`. Note, the returned `CFData` owns the + /// underlying buffer. + pub fn data(&self) -> CFData { + let data_provider = unsafe { + CGDataProviderRef::from_ptr(CGImageGetDataProvider(self.as_ptr())) + }; + data_provider.copy_data() + } + + /// Returns a cropped image. If the `rect` specifies a rectangle which lies outside of the + /// image bounds, the `None` is returned. + pub fn cropped(&self, rect: CGRect) -> Option { + let image_ptr = unsafe { CGImageCreateWithImageInRect(self.as_ptr(), rect) }; + if !image_ptr.is_null() { + Some(unsafe { CGImage::from_ptr(image_ptr) }) + } else { + None + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGImageGetTypeID() -> CFTypeID; + fn CGImageGetWidth(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetHeight(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBitsPerComponent(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBitsPerPixel(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBytesPerRow(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetColorSpace(image: ::sys::CGImageRef) -> ::sys::CGColorSpaceRef; + fn CGImageGetDataProvider(image: ::sys::CGImageRef) -> ::sys::CGDataProviderRef; + fn CGImageRelease(image: ::sys::CGImageRef); + fn CGImageCreate(width: size_t, + height: size_t, + bitsPerComponent: size_t, + bitsPerPixel: size_t, + bytesPerRow: size_t, + space: ::sys::CGColorSpaceRef, + bitmapInfo: u32, + provider: ::sys::CGDataProviderRef, + decode: *const CGFloat, + shouldInterpolate: bool, + intent: u32) + -> ::sys::CGImageRef; + fn CGImageCreateWithImageInRect(image: ::sys::CGImageRef, rect: CGRect) -> ::sys::CGImageRef; + + //fn CGImageGetAlphaInfo(image: ::sys::CGImageRef) -> CGImageAlphaInfo; + //fn CGImageCreateCopyWithColorSpace(image: ::sys::CGImageRef, space: ::sys::CGColorSpaceRef) -> ::sys::CGImageRef +} diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/lib.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/lib.rs new file mode 100644 index 0000000..aa8c684 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/lib.rs @@ -0,0 +1,41 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate libc; + +#[macro_use] +extern crate core_foundation; + +#[macro_use] +extern crate bitflags; + +#[macro_use] +extern crate foreign_types; + +pub mod base; +pub mod color; +pub mod color_space; +pub mod context; +pub mod data_provider; +#[cfg(target_os = "macos")] +pub mod display; +#[cfg(target_os = "macos")] +pub mod event; +#[cfg(target_os = "macos")] +pub mod event_source; +pub mod font; +pub mod geometry; +pub mod gradient; +#[cfg(target_os = "macos")] +pub mod window; +#[cfg(target_os = "macos")] +pub mod private; +pub mod image; +pub mod path; +pub mod sys; diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/path.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/path.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/path.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/path.rs diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/private.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/private.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/private.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/private.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.2/src/sys.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/sys.rs new file mode 100644 index 0000000..2ae5261 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.19.2/src/sys.rs @@ -0,0 +1,42 @@ +use std::os::raw::c_void; + +pub enum CGImage {} +pub type CGImageRef = *mut CGImage; + +#[repr(C)] +pub struct __CGColor(c_void); + +pub type CGColorRef = *const __CGColor; + +pub enum CGColorSpace {} +pub type CGColorSpaceRef = *mut CGColorSpace; + +pub enum CGPath {} +pub type CGPathRef = *mut CGPath; + +pub enum CGDataProvider {} +pub type CGDataProviderRef = *mut CGDataProvider; + +pub enum CGFont {} +pub type CGFontRef = *mut CGFont; + +pub enum CGContext {} +pub type CGContextRef = *mut CGContext; + +pub enum CGGradient {} +pub type CGGradientRef = *mut CGGradient; + +#[cfg(target_os = "macos")] +mod macos { + pub enum CGEvent {} + pub type CGEventRef = *mut CGEvent; + + pub enum CGEventSource {} + pub type CGEventSourceRef = *mut CGEventSource; + + pub enum CGDisplayMode {} + pub type CGDisplayModeRef = *mut CGDisplayMode; +} + +#[cfg(target_os = "macos")] +pub use self::macos::*; diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/window.rs b/third_party/cargo/vendor/core-graphics-0.19.2/src/window.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/window.rs rename to third_party/cargo/vendor/core-graphics-0.19.2/src/window.rs diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/.cargo-checksum.json b/third_party/cargo/vendor/core-graphics-0.22.2/.cargo-checksum.json new file mode 100644 index 0000000..8c4669b --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYRIGHT":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"4f4c058a2b1b415d2b94911d133a72e9046b0dc397ccb6bcdc07d8633557fe2d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"6745c3c38183d2eda9b1fa265fb0a95018db5c110cbabc00b32327d951bbe2ea","src/base.rs":"838683ff67253f4aff1d4b4177531210ca73d4e61f05c5d96a8f196b2a88c787","src/color.rs":"4c8ec4ab828cbc1b2a1538a34a51f5b380927f2f1daf187dff6f732f57a43656","src/color_space.rs":"b3d7ee8a21703c789160867cb8eb2188bd1daa193e3d030f21adb6f1a6f872de","src/context.rs":"8bda7f9ecb5be768b09a29cc3b0a4f329f55d2a2ab74030d121610283862d833","src/data_provider.rs":"b25201fdea43ea1a019c68aa5e997725d04d0824a238354ddc9f2dd8a6835cc4","src/display.rs":"cc691712c3d27342ae97f04df6032d6f682570239ba51936fcc796c61bf08c8b","src/event.rs":"84d6035ab155e702be056f4f37d0cbb76ccfa8fb9277fcbfb42c7953d0cd3937","src/event_source.rs":"d55a4f5b5e62789325028febc51bbf54c74b15ab1a4e70c6ad749a2f9753e081","src/font.rs":"cfff63d8f07d8fe497fdef258163c1bf7b3755b845fffb8e3c99a5cb45986fc8","src/geometry.rs":"8e12dc89835406bfa514de8fb58f5fd435724d1ddb97dc3a70392efbcf1c42ed","src/gradient.rs":"8ee8661706f36914d08e903840c4f07414b38ba40ea4a482d34b900ac6ac7cf9","src/image.rs":"a5a5df8c0f310455f038eeb16688015f481688cb417f8e8f424a4c1d2a1cdd57","src/lib.rs":"78264571227db6fc9194cb90d64beaff1738a501f88b5da55eb17ae42592d26f","src/path.rs":"c429afeaed999b02ac00f89a867b5fc64f1e223039079a4e0529306b734ff117","src/private.rs":"da3fd61338bab2d8e26aa5433b2e18ecd2a0a408c62e1ac2b33a0f87f2dad88a","src/sys.rs":"72cd460e499734a9394a8ec57dcb30ea0a15717452ff9fb343f22effa5d6d308","src/window.rs":"2f6c3dc958ae2c0c9e2fc5033300b96e60ed0abee9823ea1f03797d64df0911a"},"package":"269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/BUILD.bazel b/third_party/cargo/vendor/core-graphics-0.22.2/BUILD.bazel new file mode 100644 index 0000000..edda3a9 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/BUILD.bazel @@ -0,0 +1,59 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "core_graphics", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.22.2", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/core-foundation-0.9.1:core_foundation", + "//third_party/cargo/vendor/core-graphics-types-0.1.1:core_graphics_types", + "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", + "//third_party/cargo/vendor/libc-0.2.82:libc", + ], +) diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/COPYRIGHT b/third_party/cargo/vendor/core-graphics-0.22.2/COPYRIGHT similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/COPYRIGHT rename to third_party/cargo/vendor/core-graphics-0.22.2/COPYRIGHT diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/Cargo.toml b/third_party/cargo/vendor/core-graphics-0.22.2/Cargo.toml new file mode 100644 index 0000000..c97f629 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-graphics" +version = "0.22.2" +authors = ["The Servo Project Developers"] +description = "Bindings to Core Graphics for macOS" +homepage = "https://github.com/servo/core-graphics-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" +[dependencies.bitflags] +version = "1.0" + +[dependencies.core-foundation] +version = "0.9" + +[dependencies.core-graphics-types] +version = "0.1" + +[dependencies.foreign-types] +version = "0.3.0" + +[dependencies.libc] +version = "0.2" + +[features] +default = [] +elcapitan = [] +highsierra = [] diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/LICENSE-APACHE b/third_party/cargo/vendor/core-graphics-0.22.2/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.17.3/LICENSE-APACHE rename to third_party/cargo/vendor/core-graphics-0.22.2/LICENSE-APACHE diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/LICENSE-MIT b/third_party/cargo/vendor/core-graphics-0.22.2/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/LICENSE-MIT rename to third_party/cargo/vendor/core-graphics-0.22.2/LICENSE-MIT diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/README.md b/third_party/cargo/vendor/core-graphics-0.22.2/README.md new file mode 100644 index 0000000..2217568 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/README.md @@ -0,0 +1,3 @@ +# core-graphics-rs + +[![Build Status](https://travis-ci.com/servo/core-graphics-rs.svg?branch=master)](https://travis-ci.com/servo/core-graphics-rs) diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/base.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/base.rs new file mode 100644 index 0000000..25baf89 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/base.rs @@ -0,0 +1,45 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this file defines CGFloat, as well as stubbed data types. + +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +pub use core_graphics_types::base::*; + +pub const kCGImageAlphaNone: u32 = 0; +pub const kCGImageAlphaPremultipliedLast: u32 = 1; +pub const kCGImageAlphaPremultipliedFirst: u32 = 2; +pub const kCGImageAlphaLast: u32 = 3; +pub const kCGImageAlphaFirst: u32 = 4; +pub const kCGImageAlphaNoneSkipLast: u32 = 5; +pub const kCGImageAlphaNoneSkipFirst: u32 = 6; + +pub const kCGBitmapByteOrderDefault: u32 = 0 << 12; +pub const kCGBitmapByteOrder16Little: u32 = 1 << 12; +pub const kCGBitmapByteOrder32Little: u32 = 2 << 12; +pub const kCGBitmapByteOrder16Big: u32 = 3 << 12; +pub const kCGBitmapByteOrder32Big: u32 = 4 << 12; + +pub const kCGRenderingIntentDefault: u32 = 0; +pub const kCGRenderingIntentAbsoluteColorimetric: u32 = 1; +pub const kCGRenderingIntentRelativeColorimetric: u32 = 2; +pub const kCGRenderingIntentPerceptual: u32 = 3; +pub const kCGRenderingIntentSaturation: u32 = 4; + +#[cfg(target_endian = "big")] +pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Big; +#[cfg(target_endian = "big")] +pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Big; + +#[cfg(target_endian = "little")] +pub const kCGBitmapByteOrder16Host: u32 = kCGBitmapByteOrder16Little; +#[cfg(target_endian = "little")] +pub const kCGBitmapByteOrder32Host: u32 = kCGBitmapByteOrder32Little; diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/color.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/color.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/color.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/color.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/color_space.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/color_space.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/color_space.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/color_space.rs diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/context.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/context.rs new file mode 100644 index 0000000..4efc0f7 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/context.rs @@ -0,0 +1,775 @@ +// Copyright 2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::CGFloat; +use color_space::CGColorSpace; +use core_foundation::base::{CFTypeID, TCFType}; +use font::{CGFont, CGGlyph}; +use geometry::{CGPoint, CGSize}; +use gradient::{CGGradient, CGGradientDrawingOptions}; +use color::CGColor; +use path::CGPathRef; +use libc::{c_int, size_t}; +use std::os::raw::c_void; + +use std::cmp; +use std::ptr; +use std::slice; +use geometry::{CGAffineTransform, CGRect}; +use image::CGImage; +use foreign_types::{ForeignType, ForeignTypeRef}; + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGBlendMode { + Normal = 0, + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + SoftLight, + HardLight, + Difference, + Exclusion, + Hue, + Saturation, + Color, + Luminosity, + // 10.5 and up: + Clear, + Copy, + SourceIn, + SourceOut, + SourceAtop, + DestinationOver, + DestinationIn, + DestinationOut, + DestinationAtop, + Xor, + PlusDarker, + PlusLighter, +} + +#[repr(C)] +pub enum CGTextDrawingMode { + CGTextFill, + CGTextStroke, + CGTextFillStroke, + CGTextInvisible, + CGTextFillClip, + CGTextStrokeClip, + CGTextFillStrokeClip, + CGTextClip +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGLineCap { + CGLineCapButt, + CGLineCapRound, + CGLineCapSquare, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGLineJoin { + CGLineJoinMiter, + CGLineJoinRound, + CGLineJoinBevel, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGPathDrawingMode { + CGPathFill, + CGPathEOFill, + CGPathStroke, + CGPathFillStroke, + CGPathEOFillStroke, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGInterpolationQuality { + CGInterpolationQualityDefault, + CGInterpolationQualityNone, + CGInterpolationQualityLow, + CGInterpolationQualityMedium, + CGInterpolationQualityHigh, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGContext; + fn drop = |cs| CGContextRelease(cs); + fn clone = |p| CGContextRetain(p); + pub struct CGContext; + pub struct CGContextRef; +} + +impl CGContext { + pub fn type_id() -> CFTypeID { + unsafe { + CGContextGetTypeID() + } + } + + /// Creates a `CGContext` instance from an existing [`CGContextRef`] pointer. + /// + /// This funtion will internally call [`CGRetain`] and hence there is no need to call it explicitly. + /// + /// This function is particularly useful for cases when the context is not instantiated/managed + /// by the caller, but it's retrieve via other means (e.g., by calling the method [`NSGraphicsContext::CGContext`] + /// in a cocoa application). + /// + /// [`CGContextRef`]: https://developer.apple.com/documentation/coregraphics/cgcontextref + /// [`CGRetain`]: https://developer.apple.com/documentation/coregraphics/1586506-cgcontextretain + /// [`NSGraphicsContext::CGContext`]: https://developer.apple.com/documentation/appkit/nsgraphicscontext/1535352-currentcontext + pub unsafe fn from_existing_context_ptr(ctx: *mut ::sys::CGContext) -> CGContext { + CGContextRetain(ctx); + Self::from_ptr(ctx) + } + + pub fn create_bitmap_context(data: Option<*mut c_void>, + width: size_t, + height: size_t, + bits_per_component: size_t, + bytes_per_row: size_t, + space: &CGColorSpace, + bitmap_info: u32) + -> CGContext { + unsafe { + let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()), + width, + height, + bits_per_component, + bytes_per_row, + space.as_ptr(), + bitmap_info); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn data(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut( + CGBitmapContextGetData(self.as_ptr()) as *mut u8, + (self.height() * self.bytes_per_row()) as usize) + } + } +} + +impl CGContextRef { + pub fn flush(&self) { + unsafe { + CGContextFlush(self.as_ptr()) + } + } + + pub fn width(&self) -> size_t { + unsafe { + CGBitmapContextGetWidth(self.as_ptr()) + } + } + + pub fn height(&self) -> size_t { + unsafe { + CGBitmapContextGetHeight(self.as_ptr()) + } + } + + pub fn bytes_per_row(&self) -> size_t { + unsafe { + CGBitmapContextGetBytesPerRow(self.as_ptr()) + } + } + + pub fn clip_bounding_box(&self) -> CGRect { + unsafe { + CGContextGetClipBoundingBox(self.as_ptr()) + } + } + + pub fn set_fill_color(&self, color: &CGColor) { + unsafe { + CGContextSetFillColorWithColor(self.as_ptr(), color.as_concrete_TypeRef()); + } + } + + pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetRGBFillColor(self.as_ptr(), red, green, blue, alpha) + } + } + + pub fn set_rgb_stroke_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetRGBStrokeColor(self.as_ptr(), red, green, blue, alpha) + } + } + + pub fn set_gray_fill_color(&self, gray: CGFloat, alpha: CGFloat) { + unsafe { + CGContextSetGrayFillColor(self.as_ptr(), gray, alpha) + } + } + + pub fn set_blend_mode(&self, blend_mode: CGBlendMode) { + unsafe { + CGContextSetBlendMode(self.as_ptr(), blend_mode) + } + } + + pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) { + unsafe { + CGContextSetAllowsFontSmoothing(self.as_ptr(), allows_font_smoothing) + } + } + + pub fn set_font_smoothing_style(&self, style: i32) { + unsafe { + CGContextSetFontSmoothingStyle(self.as_ptr(), style as _); + } + } + + pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) { + unsafe { + CGContextSetShouldSmoothFonts(self.as_ptr(), should_smooth_fonts) + } + } + + pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) { + unsafe { + CGContextSetAllowsAntialiasing(self.as_ptr(), allows_antialiasing) + } + } + + pub fn set_should_antialias(&self, should_antialias: bool) { + unsafe { + CGContextSetShouldAntialias(self.as_ptr(), should_antialias) + } + } + + pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) { + unsafe { + CGContextSetAllowsFontSubpixelQuantization(self.as_ptr(), allows_font_subpixel_quantization) + } + } + + pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) { + unsafe { + CGContextSetShouldSubpixelQuantizeFonts(self.as_ptr(), should_subpixel_quantize_fonts) + } + } + + pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) { + unsafe { + CGContextSetAllowsFontSubpixelPositioning(self.as_ptr(), allows_font_subpixel_positioning) + } + } + + pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) { + unsafe { + CGContextSetShouldSubpixelPositionFonts(self.as_ptr(), should_subpixel_position_fonts) + } + } + + pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) { + unsafe { + CGContextSetTextDrawingMode(self.as_ptr(), mode) + } + } + + pub fn set_line_cap(&self, cap: CGLineCap) { + unsafe { + CGContextSetLineCap(self.as_ptr(), cap) + } + } + + pub fn set_line_dash(&self, phase: CGFloat, lengths: &[CGFloat]) { + unsafe { + CGContextSetLineDash(self.as_ptr(), phase, lengths.as_ptr(), lengths.len()) + } + } + + pub fn set_line_join(&self, join: CGLineJoin) { + unsafe { + CGContextSetLineJoin(self.as_ptr(), join) + } + } + + pub fn set_line_width(&self, width: CGFloat) { + unsafe { + CGContextSetLineWidth(self.as_ptr(), width) + } + } + + pub fn set_miter_limit(&self, limit: CGFloat) { + unsafe { + CGContextSetMiterLimit(self.as_ptr(), limit) + } + } + + pub fn add_path(&self, path: &CGPathRef) { + unsafe { + CGContextAddPath(self.as_ptr(), path.as_ptr()); + } + } + + pub fn add_curve_to_point(&self, + cp1x: CGFloat, + cp1y: CGFloat, + cp2x: CGFloat, + cp2y: CGFloat, + x: CGFloat, + y: CGFloat) { + unsafe { + CGContextAddCurveToPoint(self.as_ptr(), + cp1x, cp1y, + cp2x, cp2y, + x, y); + } + } + + pub fn add_quad_curve_to_point(&self, + cpx: CGFloat, + cpy: CGFloat, + x: CGFloat, + y: CGFloat) { + unsafe { + CGContextAddQuadCurveToPoint(self.as_ptr(), + cpx, cpy, + x, y); + } + } + + pub fn add_line_to_point(&self, x: CGFloat, y: CGFloat) { + unsafe { + CGContextAddLineToPoint(self.as_ptr(), x, y); + } + } + + pub fn begin_path(&self) { + unsafe { + CGContextBeginPath(self.as_ptr()); + } + } + + pub fn close_path(&self) { + unsafe { + CGContextClosePath(self.as_ptr()); + } + } + + pub fn move_to_point(&self, x: CGFloat, y: CGFloat) { + unsafe { + CGContextMoveToPoint(self.as_ptr(), x, y); + } + } + + pub fn clip(&self) { + unsafe { + CGContextClip(self.as_ptr()); + } + } + + pub fn eo_clip(&self) { + unsafe { + CGContextEOClip(self.as_ptr()); + } + } + + pub fn draw_path(&self, mode: CGPathDrawingMode) { + unsafe { + CGContextDrawPath(self.as_ptr(), mode); + } + } + + pub fn fill_path(&self) { + unsafe { + CGContextFillPath(self.as_ptr()); + } + } + + pub fn eo_fill_path(&self) { + unsafe { + CGContextEOFillPath(self.as_ptr()); + } + } + + pub fn stroke_path(&self) { + unsafe { + CGContextStrokePath(self.as_ptr()); + } + } + + pub fn fill_rect(&self, rect: CGRect) { + unsafe { + CGContextFillRect(self.as_ptr(), rect) + } + } + + pub fn fill_rects(&self, rects: &[CGRect]) { + unsafe { + CGContextFillRects(self.as_ptr(), rects.as_ptr(), rects.len()) + } + } + + pub fn clear_rect(&self, rect: CGRect) { + unsafe { + CGContextClearRect(self.as_ptr(), rect) + } + } + + pub fn stroke_rect(&self, rect: CGRect) { + unsafe { + CGContextStrokeRect(self.as_ptr(), rect) + } + } + + pub fn stroke_rect_with_width(&self, rect: CGRect, width: CGFloat) { + unsafe { + CGContextStrokeRectWithWidth(self.as_ptr(), rect, width) + } + } + + pub fn clip_to_rect(&self, rect: CGRect) { + unsafe { + CGContextClipToRect(self.as_ptr(), rect) + } + } + + pub fn clip_to_rects(&self, rects: &[CGRect]) { + unsafe { + CGContextClipToRects(self.as_ptr(), rects.as_ptr(), rects.len()) + } + } + + pub fn clip_to_mask(&self, rect: CGRect, image: &CGImage) { + unsafe { + CGContextClipToMask(self.as_ptr(), rect, image.as_ptr()) + } + } + + pub fn replace_path_with_stroked_path(&self) { + unsafe { + CGContextReplacePathWithStrokedPath(self.as_ptr()) + } + } + + pub fn fill_ellipse_in_rect(&self, rect: CGRect) { + unsafe { + CGContextFillEllipseInRect(self.as_ptr(), rect) + } + } + + pub fn stroke_ellipse_in_rect(&self, rect: CGRect) { + unsafe { + CGContextStrokeEllipseInRect(self.as_ptr(), rect) + } + } + + pub fn stroke_line_segments(&self, points: &[CGPoint]) { + unsafe { + CGContextStrokeLineSegments(self.as_ptr(), points.as_ptr(), points.len()) + } + } + + pub fn set_interpolation_quality(&self, quality: CGInterpolationQuality) { + unsafe { + CGContextSetInterpolationQuality(self.as_ptr(), quality); + } + } + + pub fn get_interpolation_quality(&self) -> CGInterpolationQuality { + unsafe { + CGContextGetInterpolationQuality(self.as_ptr()) + + } + } + + pub fn draw_image(&self, rect: CGRect, image: &CGImage) { + unsafe { + CGContextDrawImage(self.as_ptr(), rect, image.as_ptr()); + } + } + + pub fn create_image(&self) -> Option { + let image = unsafe { CGBitmapContextCreateImage(self.as_ptr()) }; + if !image.is_null() { + Some(unsafe { CGImage::from_ptr(image) }) + } else { + None + } + } + + pub fn set_font(&self, font: &CGFont) { + unsafe { + CGContextSetFont(self.as_ptr(), font.as_ptr()) + } + } + + pub fn set_font_size(&self, size: CGFloat) { + unsafe { + CGContextSetFontSize(self.as_ptr(), size) + } + } + + pub fn set_text_matrix(&self, t: &CGAffineTransform) { + unsafe { + CGContextSetTextMatrix(self.as_ptr(), *t) + } + } + + pub fn set_text_position(&self, x: CGFloat, y: CGFloat) { + unsafe { + CGContextSetTextPosition(self.as_ptr(), x, y) + } + } + + pub fn show_glyphs_at_positions(&self, glyphs: &[CGGlyph], positions: &[CGPoint]) { + unsafe { + let count = cmp::min(glyphs.len(), positions.len()); + CGContextShowGlyphsAtPositions(self.as_ptr(), + glyphs.as_ptr(), + positions.as_ptr(), + count) + } + } + + pub fn save(&self) { + unsafe { + CGContextSaveGState(self.as_ptr()); + } + } + + pub fn restore(&self) { + unsafe { + CGContextRestoreGState(self.as_ptr()); + } + } + + pub fn translate(&self, tx: CGFloat, ty: CGFloat) { + unsafe { + CGContextTranslateCTM(self.as_ptr(), tx, ty); + } + } + + pub fn scale(&self, sx: CGFloat, sy: CGFloat) { + unsafe { + CGContextScaleCTM(self.as_ptr(), sx, sy); + } + } + + pub fn rotate(&self, angle: CGFloat) { + unsafe { + CGContextRotateCTM(self.as_ptr(), angle); + } + } + + pub fn get_ctm(&self) -> CGAffineTransform { + unsafe { + CGContextGetCTM(self.as_ptr()) + } + } + + pub fn concat_ctm(&self, transform: CGAffineTransform) { + unsafe { + CGContextConcatCTM(self.as_ptr(), transform) + } + } + + pub fn draw_linear_gradient(&self, gradient: &CGGradient, start_point: CGPoint, end_point: CGPoint, options: CGGradientDrawingOptions) { + unsafe { + CGContextDrawLinearGradient(self.as_ptr(), gradient.as_ptr(), start_point, end_point, options); + } + } + + pub fn draw_radial_gradient(&self, gradient: &CGGradient, start_center: CGPoint, start_radius: CGFloat, end_center: CGPoint, end_radius: CGFloat, options: CGGradientDrawingOptions) { + unsafe { + CGContextDrawRadialGradient(self.as_ptr(), gradient.as_ptr(), start_center, start_radius, end_center, end_radius, options); + } + } + + pub fn set_shadow(&self, offset: CGSize, blur: CGFloat) { + unsafe { + CGContextSetShadow(self.as_ptr(), offset, blur); + } + } + + pub fn set_shadow_with_color(&self, offset: CGSize, blur: CGFloat, color: &CGColor) { + unsafe { + CGContextSetShadowWithColor(self.as_ptr(), offset, blur, color.as_concrete_TypeRef()); + } + } +} + +#[test] +fn create_bitmap_context_test() { + use geometry::*; + + let cs = CGColorSpace::create_device_rgb(); + let ctx = CGContext::create_bitmap_context(None, + 16, 8, + 8, 0, + &cs, + ::base::kCGImageAlphaPremultipliedLast); + ctx.set_rgb_fill_color(1.,0.,1.,1.); + ctx.set_miter_limit(4.); + ctx.fill_rect(CGRect::new(&CGPoint::new(0.,0.), &CGSize::new(8.,8.))); + let img = ctx.create_image().unwrap(); + assert_eq!(16, img.width()); + assert_eq!(8, img.height()); + assert_eq!(8, img.bits_per_component()); + assert_eq!(32, img.bits_per_pixel()); + let data = img.data(); + assert_eq!(255, data.bytes()[0]); + assert_eq!(0, data.bytes()[1]); + assert_eq!(255, data.bytes()[2]); + assert_eq!(255, data.bytes()[3]); +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGContextRetain(c: ::sys::CGContextRef) -> ::sys::CGContextRef; + fn CGContextRelease(c: ::sys::CGContextRef); + + fn CGBitmapContextCreate(data: *mut c_void, + width: size_t, + height: size_t, + bitsPerComponent: size_t, + bytesPerRow: size_t, + space: ::sys::CGColorSpaceRef, + bitmapInfo: u32) + -> ::sys::CGContextRef; + fn CGBitmapContextGetData(context: ::sys::CGContextRef) -> *mut c_void; + fn CGBitmapContextGetWidth(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextGetHeight(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextGetBytesPerRow(context: ::sys::CGContextRef) -> size_t; + fn CGBitmapContextCreateImage(context: ::sys::CGContextRef) -> ::sys::CGImageRef; + fn CGContextGetTypeID() -> CFTypeID; + fn CGContextGetClipBoundingBox(c: ::sys::CGContextRef) -> CGRect; + fn CGContextFlush(c: ::sys::CGContextRef); + fn CGContextSetBlendMode(c: ::sys::CGContextRef, blendMode: CGBlendMode); + fn CGContextSetAllowsFontSmoothing(c: ::sys::CGContextRef, allowsFontSmoothing: bool); + fn CGContextSetShouldSmoothFonts(c: ::sys::CGContextRef, shouldSmoothFonts: bool); + fn CGContextSetFontSmoothingStyle(c: ::sys::CGContextRef, style: c_int); + fn CGContextSetAllowsAntialiasing(c: ::sys::CGContextRef, allowsAntialiasing: bool); + fn CGContextSetShouldAntialias(c: ::sys::CGContextRef, shouldAntialias: bool); + fn CGContextSetAllowsFontSubpixelQuantization(c: ::sys::CGContextRef, + allowsFontSubpixelQuantization: bool); + fn CGContextSetShouldSubpixelQuantizeFonts(c: ::sys::CGContextRef, + shouldSubpixelQuantizeFonts: bool); + fn CGContextSetAllowsFontSubpixelPositioning(c: ::sys::CGContextRef, + allowsFontSubpixelPositioning: bool); + fn CGContextSetShouldSubpixelPositionFonts(c: ::sys::CGContextRef, + shouldSubpixelPositionFonts: bool); + fn CGContextSetTextDrawingMode(c: ::sys::CGContextRef, mode: CGTextDrawingMode); + fn CGContextSetFillColorWithColor(c: ::sys::CGContextRef, color: ::sys::CGColorRef); + fn CGContextSetLineCap(c: ::sys::CGContextRef, cap: CGLineCap); + fn CGContextSetLineDash(c: ::sys::CGContextRef, phase: CGFloat, lengths: *const CGFloat, count: size_t); + fn CGContextSetLineJoin(c: ::sys::CGContextRef, join: CGLineJoin); + fn CGContextSetLineWidth(c: ::sys::CGContextRef, width: CGFloat); + fn CGContextSetMiterLimit(c: ::sys::CGContextRef, limit: CGFloat); + + fn CGContextAddPath(c: ::sys::CGContextRef, path: ::sys::CGPathRef); + fn CGContextAddCurveToPoint(c: ::sys::CGContextRef, + cp1x: CGFloat, + cp1y: CGFloat, + cp2x: CGFloat, + cp2y: CGFloat, + x: CGFloat, + y: CGFloat); + fn CGContextAddQuadCurveToPoint(c: ::sys::CGContextRef, + cpx: CGFloat, + cpy: CGFloat, + x: CGFloat, + y: CGFloat); + fn CGContextAddLineToPoint(c: ::sys::CGContextRef, + x: CGFloat, + y: CGFloat); + fn CGContextBeginPath(c: ::sys::CGContextRef); + fn CGContextClosePath(c: ::sys::CGContextRef); + fn CGContextMoveToPoint(c: ::sys::CGContextRef, + x: CGFloat, + y: CGFloat); + fn CGContextDrawPath(c: ::sys::CGContextRef, mode: CGPathDrawingMode); + fn CGContextFillPath(c: ::sys::CGContextRef); + fn CGContextEOFillPath(c: ::sys::CGContextRef); + fn CGContextClip(c: ::sys::CGContextRef); + fn CGContextEOClip(c: ::sys::CGContextRef); + fn CGContextStrokePath(c: ::sys::CGContextRef); + fn CGContextSetRGBFillColor(context: ::sys::CGContextRef, + red: CGFloat, + green: CGFloat, + blue: CGFloat, + alpha: CGFloat); + fn CGContextSetRGBStrokeColor(context: ::sys::CGContextRef, + red: CGFloat, + green: CGFloat, + blue: CGFloat, + alpha: CGFloat); + fn CGContextSetGrayFillColor(context: ::sys::CGContextRef, gray: CGFloat, alpha: CGFloat); + fn CGContextClearRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextFillRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextFillRects(context: ::sys::CGContextRef, + rects: *const CGRect, + count: size_t); + fn CGContextStrokeRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextStrokeRectWithWidth(context: ::sys::CGContextRef, + rect: CGRect, + width: CGFloat); + fn CGContextClipToRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextClipToRects(context: ::sys::CGContextRef, + rects: *const CGRect, + count: size_t); + fn CGContextClipToMask(ctx: ::sys::CGContextRef, rect: CGRect, mask: ::sys::CGImageRef); + fn CGContextReplacePathWithStrokedPath(context: ::sys::CGContextRef); + fn CGContextFillEllipseInRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextStrokeEllipseInRect(context: ::sys::CGContextRef, + rect: CGRect); + fn CGContextStrokeLineSegments(context: ::sys::CGContextRef, + points: *const CGPoint, + count: size_t); + fn CGContextDrawImage(c: ::sys::CGContextRef, rect: CGRect, image: ::sys::CGImageRef); + fn CGContextSetInterpolationQuality(c: ::sys::CGContextRef, quality: CGInterpolationQuality); + fn CGContextGetInterpolationQuality(c: ::sys::CGContextRef) -> CGInterpolationQuality; + fn CGContextSetFont(c: ::sys::CGContextRef, font: ::sys::CGFontRef); + fn CGContextSetFontSize(c: ::sys::CGContextRef, size: CGFloat); + fn CGContextSetTextMatrix(c: ::sys::CGContextRef, t: CGAffineTransform); + fn CGContextSetTextPosition(c: ::sys::CGContextRef, x: CGFloat, y: CGFloat); + fn CGContextShowGlyphsAtPositions(c: ::sys::CGContextRef, + glyphs: *const CGGlyph, + positions: *const CGPoint, + count: size_t); + + fn CGContextSaveGState(c: ::sys::CGContextRef); + fn CGContextRestoreGState(c: ::sys::CGContextRef); + fn CGContextTranslateCTM(c: ::sys::CGContextRef, tx: CGFloat, ty: CGFloat); + fn CGContextScaleCTM(c: ::sys::CGContextRef, sx: CGFloat, sy: CGFloat); + fn CGContextRotateCTM(c: ::sys::CGContextRef, angle: CGFloat); + fn CGContextGetCTM(c: ::sys::CGContextRef) -> CGAffineTransform; + fn CGContextConcatCTM(c: ::sys::CGContextRef, transform: CGAffineTransform); + + fn CGContextDrawLinearGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startPoint: CGPoint, endPoint: CGPoint, options: CGGradientDrawingOptions); + fn CGContextDrawRadialGradient(c: ::sys::CGContextRef, gradient: ::sys::CGGradientRef, startCenter: CGPoint, startRadius: CGFloat, endCenter:CGPoint, endRadius:CGFloat, options: CGGradientDrawingOptions); + + fn CGContextSetShadow(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat); + fn CGContextSetShadowWithColor(c: ::sys::CGContextRef, offset: CGSize, blur: CGFloat, color: ::sys::CGColorRef); +} + diff --git a/third_party/cargo/vendor/core-graphics-0.17.3/src/data_provider.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/data_provider.rs similarity index 75% rename from third_party/cargo/vendor/core-graphics-0.17.3/src/data_provider.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/data_provider.rs index b6388fc..e8bb0a0 100644 --- a/third_party/cargo/vendor/core-graphics-0.17.3/src/data_provider.rs +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/data_provider.rs @@ -50,17 +50,17 @@ impl CGDataProvider { /// /// The `CGDataProvider` object takes ownership of the reference. Once the data provider /// is destroyed, the reference count of the buffer is automatically decremented. - pub fn from_buffer(buffer: Arc>) -> Self { + pub fn from_buffer + Sync + Send>(buffer: Arc) -> Self { unsafe { - let ptr = (*buffer).as_ptr() as *const c_void; - let len = buffer.len() as size_t; - let info = mem::transmute::>, *mut c_void>(buffer); - let result = CGDataProviderCreateWithData(info, ptr, len, Some(release)); + let ptr = (*buffer).as_ref().as_ptr() as *const c_void; + let len = (*buffer).as_ref().len() as size_t; + let info = Arc::into_raw(buffer) as *mut c_void; + let result = CGDataProviderCreateWithData(info, ptr, len, Some(release::)); return CGDataProvider::from_ptr(result); } - unsafe extern "C" fn release(info: *mut c_void, _: *const c_void, _: size_t) { - drop(mem::transmute::<*mut c_void, Arc>>(info)) + unsafe extern "C" fn release(info: *mut c_void, _: *const c_void, _: size_t) { + drop(Arc::from_raw(info as *mut T)) } } @@ -77,14 +77,14 @@ impl CGDataProvider { /// /// This is double-boxed because the Core Text API requires that the userdata be a single /// pointer. - pub unsafe fn from_custom_data(custom_data: Box>) -> Self { + pub unsafe fn from_custom_data(custom_data: Box>) -> Self { let (ptr, len) = (custom_data.ptr() as *const c_void, custom_data.len()); - let userdata = mem::transmute::>, &mut c_void>(custom_data); + let userdata = mem::transmute::>, &mut c_void>(custom_data); let data_provider = CGDataProviderCreateWithData(userdata, ptr, len, Some(release)); return CGDataProvider::from_ptr(data_provider); unsafe extern "C" fn release(info: *mut c_void, _: *const c_void, _: size_t) { - drop(mem::transmute::<*mut c_void, Box>>(info)) + drop(mem::transmute::<*mut c_void, Box>>(info)) } } } @@ -106,6 +106,43 @@ pub trait CustomData { unsafe fn len(&self) -> usize; } +#[test] +fn test_data_provider() { + let l = vec![5]; + CGDataProvider::from_buffer(Arc::new(l)); + + let l = vec![5]; + CGDataProvider::from_buffer(Arc::new(l.into_boxed_slice())); + + // Make sure the buffer is actually dropped + use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; + struct VecWrapper { + inner: Vec, + dropped: Arc, + } + + impl Drop for VecWrapper { + fn drop(&mut self) { + self.dropped.store(true, SeqCst) + } + } + + impl std::convert::AsRef<[u8]> for VecWrapper { + fn as_ref(&self) -> &[u8] { + &self.inner + } + } + + let dropped = Arc::new(AtomicBool::default()); + let l = Arc::new(VecWrapper {inner: vec![5], dropped: dropped.clone() }); + let m = l.clone(); + let dp = CGDataProvider::from_buffer(l); + drop(m); + assert!(!dropped.load(SeqCst)); + drop(dp); + assert!(dropped.load(SeqCst)) +} + #[link(name = "CoreGraphics", kind = "framework")] extern { fn CGDataProviderCopyData(provider: ::sys::CGDataProviderRef) -> CFDataRef; diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/display.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/display.rs new file mode 100644 index 0000000..f677408 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/display.rs @@ -0,0 +1,718 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use libc; +use std::ptr; +use std::ops::Deref; + +pub use base::{CGError, boolean_t}; +pub use geometry::{CGRect, CGPoint, CGSize}; + +use core_foundation::string::{CFString, CFStringRef}; +use core_foundation::base::{CFRetain, TCFType}; +use image::CGImage; +use foreign_types::ForeignType; + +pub type CGDirectDisplayID = u32; +pub type CGWindowID = u32; + +pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID; +pub const kCGNullDirectDisplayID: CGDirectDisplayID = 0 as CGDirectDisplayID; + +pub type CGWindowListOption = u32; + +pub const kCGWindowListOptionAll: CGWindowListOption = 0; +pub const kCGWindowListOptionOnScreenOnly: CGWindowListOption = 1 << 0; +pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1; +pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2; +pub const kCGWindowListOptionIncludingWindow: CGWindowListOption = 1 << 3; +pub const kCGWindowListExcludeDesktopElements: CGWindowListOption = 1 << 4; + +pub type CGWindowImageOption = u32; + +pub const kCGWindowImageDefault: CGWindowImageOption = 0; +pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0; +pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1; +pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2; +pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3; +pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4; + +pub const kDisplayModeValidFlag: u32 = 0x00000001; +pub const kDisplayModeSafeFlag: u32 = 0x00000002; +pub const kDisplayModeDefaultFlag: u32 = 0x00000004; +pub const kDisplayModeAlwaysShowFlag: u32 = 0x00000008; +pub const kDisplayModeNeverShowFlag: u32 = 0x00000080; +pub const kDisplayModeNotResizeFlag: u32 = 0x00000010; +pub const kDisplayModeRequiresPanFlag: u32 = 0x00000020; +pub const kDisplayModeInterlacedFlag: u32 = 0x00000040; +pub const kDisplayModeSimulscanFlag: u32 = 0x00000100; +pub const kDisplayModeBuiltInFlag: u32 = 0x00000400; +pub const kDisplayModeNotPresetFlag: u32 = 0x00000200; +pub const kDisplayModeStretchedFlag: u32 = 0x00000800; +pub const kDisplayModeNotGraphicsQualityFlag: u32 = 0x00001000; +pub const kDisplayModeValidateAgainstDisplay: u32 = 0x00002000; +pub const kDisplayModeTelevisionFlag: u32 = 0x00100000; +pub const kDisplayModeValidForMirroringFlag: u32 = 0x00200000; +pub const kDisplayModeAcceleratorBackedFlag: u32 = 0x00400000; +pub const kDisplayModeValidForHiResFlag: u32 = 0x00800000; +pub const kDisplayModeValidForAirPlayFlag: u32 = 0x01000000; +pub const kDisplayModeNativeFlag: u32 = 0x02000000; + +pub const kDisplayModeSafetyFlags: u32 = 0x00000007; + +pub const IO1BitIndexedPixels: &str = "P"; +pub const IO2BitIndexedPixels: &str = "PP"; +pub const IO4BitIndexedPixels: &str = "PPPP"; +pub const IO8BitIndexedPixels: &str = "PPPPPPPP"; +pub const IO16BitDirectPixels: &str = "-RRRRRGGGGGBBBBB"; +pub const IO32BitDirectPixels: &str = "--------RRRRRRRRGGGGGGGGBBBBBBBB"; +pub const kIO30BitDirectPixels: &str = "--RRRRRRRRRRGGGGGGGGGGBBBBBBBBBB"; +pub const kIO64BitDirectPixels: &str = "-16R16G16B16"; +pub const kIO16BitFloatPixels: &str = "-16FR16FG16FB16"; +pub const kIO32BitFloatPixels: &str = "-32FR32FG32FB32"; +pub const IOYUV422Pixels: &str = "Y4U2V2"; +pub const IO8BitOverlayPixels: &str = "O8"; + + +pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent }; +pub use core_foundation::array::{ CFArray, CFArrayRef }; +pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex }; +pub use core_foundation::base::{ CFIndex, CFRelease, CFTypeRef }; + +pub type CGDisplayConfigRef = *mut libc::c_void; + +#[repr(u32)] +#[derive(Clone, Copy)] +pub enum CGConfigureOption { + ConfigureForAppOnly = 0, + ConfigureForSession = 1, + ConfigurePermanently = 2, +} + +#[derive(Copy, Clone, Debug)] +pub struct CGDisplay { + pub id: CGDirectDisplayID, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGDisplayMode; + fn drop = CGDisplayModeRelease; + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGDisplayMode; + pub struct CGDisplayModeRef; +} + +impl CGDisplay { + #[inline] + pub fn new(id: CGDirectDisplayID) -> CGDisplay { + CGDisplay { id: id } + } + + /// Returns the the main display. + #[inline] + pub fn main() -> CGDisplay { + CGDisplay::new(unsafe { CGMainDisplayID() }) + } + + /// A value that will never correspond to actual hardware. + pub fn null_display() -> CGDisplay { + CGDisplay::new(kCGNullDirectDisplayID) + } + + /// Returns the bounds of a display in the global display coordinate space. + #[inline] + pub fn bounds(&self) -> CGRect { + unsafe { CGDisplayBounds(self.id) } + } + + /// Returns information about a display's current configuration. + #[inline] + pub fn display_mode(&self) -> Option { + unsafe { + let mode_ref = CGDisplayCopyDisplayMode(self.id); + if !mode_ref.is_null() { + Some(CGDisplayMode::from_ptr(mode_ref)) + } else { + None + } + } + } + + /// Begins a new set of display configuration changes. + pub fn begin_configuration(&self) -> Result { + unsafe { + let mut config_ref: CGDisplayConfigRef = ptr::null_mut(); + let result = CGBeginDisplayConfiguration(&mut config_ref); + if result == 0 { + Ok(config_ref) + } else { + Err(result) + } + } + } + + /// Cancels a set of display configuration changes. + pub fn cancel_configuration(&self, config_ref: &CGDisplayConfigRef) -> Result<(), CGError> { + let result = unsafe { CGCancelDisplayConfiguration(*config_ref) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Completes a set of display configuration changes. + pub fn complete_configuration( + &self, + config_ref: &CGDisplayConfigRef, + option: CGConfigureOption, + ) -> Result<(), CGError> { + let result = unsafe { CGCompleteDisplayConfiguration(*config_ref, option) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Configures the display mode of a display. + pub fn configure_display_with_display_mode( + &self, + config_ref: &CGDisplayConfigRef, + display_mode: &CGDisplayMode, + ) -> Result<(), CGError> { + let result = unsafe { + CGConfigureDisplayWithDisplayMode( + *config_ref, + self.id, + display_mode.as_ptr(), + ptr::null(), + ) + }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Configures the origin of a display in the global display coordinate space. + pub fn configure_display_origin( + &self, + config_ref: &CGDisplayConfigRef, + x: i32, + y: i32, + ) -> Result<(), CGError> { + let result = unsafe { CGConfigureDisplayOrigin(*config_ref, self.id, x, y) }; + + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Changes the configuration of a mirroring set. + pub fn configure_display_mirror_of_display( + &self, + config_ref: &CGDisplayConfigRef, + master: &CGDisplay, + ) -> Result<(), CGError> { + let result = unsafe { CGConfigureDisplayMirrorOfDisplay(*config_ref, self.id, master.id) }; + + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Returns an image containing the contents of the specified display. + #[inline] + pub fn image(&self) -> Option { + unsafe { + let image_ref = CGDisplayCreateImage(self.id); + if !image_ref.is_null() { + Some(CGImage::from_ptr(image_ref)) + } else { + None + } + } + } + + /// Returns a composite image based on a dynamically generated list of + /// windows. + #[inline] + pub fn screenshot( + bounds: CGRect, + list_option: CGWindowListOption, + window_id: CGWindowID, + image_option: CGWindowImageOption, + ) -> Option { + unsafe { + let image_ref = CGWindowListCreateImage(bounds, list_option, window_id, image_option); + if !image_ref.is_null() { + Some(CGImage::from_ptr(image_ref)) + } else { + None + } + } + } + + /// Returns a composite image of the specified windows. + #[inline] + pub fn screenshot_from_windows( + bounds: CGRect, + windows: CFArray, + image_option: CGWindowImageOption, + ) -> Option { + unsafe { + let image_ref = CGWindowListCreateImageFromArray( + bounds, + windows.as_concrete_TypeRef(), + image_option, + ); + if !image_ref.is_null() { + Some(CGImage::from_ptr(image_ref)) + } else { + None + } + } + } + + /// Generates and returns information about the selected windows in the + /// current user session. + pub fn window_list_info( + option: CGWindowListOption, + relative_to_window: Option, + ) -> Option { + let relative_to_window = relative_to_window.unwrap_or(kCGNullWindowID); + let array_ref = unsafe { CGWindowListCopyWindowInfo(option, relative_to_window) }; + if !array_ref.is_null() { + Some(unsafe { TCFType::wrap_under_create_rule(array_ref) }) + } else { + None + } + } + + /// Returns a Boolean value indicating whether a display is active. + #[inline] + pub fn is_active(&self) -> bool { + unsafe { CGDisplayIsActive(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is always in a + /// mirroring set. + #[inline] + pub fn is_always_in_mirror_set(&self) -> bool { + unsafe { CGDisplayIsAlwaysInMirrorSet(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is sleeping (and is + /// therefore not drawable.) + #[inline] + pub fn is_asleep(&self) -> bool { + unsafe { CGDisplayIsAsleep(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is built-in, such as + /// the internal display in portable systems. + #[inline] + pub fn is_builtin(&self) -> bool { + unsafe { CGDisplayIsBuiltin(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is in a hardware + /// mirroring set. + #[inline] + pub fn is_in_hw_mirror_set(&self) -> bool { + unsafe { CGDisplayIsInHWMirrorSet(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is in a mirroring set. + #[inline] + pub fn is_in_mirror_set(&self) -> bool { + unsafe { CGDisplayIsInMirrorSet(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is the main display. + #[inline] + pub fn is_main(&self) -> bool { + unsafe { CGDisplayIsMain(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is connected or online. + #[inline] + pub fn is_online(&self) -> bool { + unsafe { CGDisplayIsOnline(self.id) != 0 } + } + + /// Returns a boolean indicating whether Quartz is using OpenGL-based + /// window acceleration (Quartz Extreme) to render in a display. + #[inline] + pub fn uses_open_gl_acceleration(&self) -> bool { + unsafe { CGDisplayUsesOpenGLAcceleration(self.id) != 0 } + } + + /// Returns a boolean indicating whether a display is running in a stereo + /// graphics mode. + #[inline] + pub fn is_stereo(&self) -> bool { + unsafe { CGDisplayIsStereo(self.id) != 0 } + } + + /// For a secondary display in a mirroring set, returns the primary + /// display. + #[inline] + pub fn mirrors_display(&self) -> CGDirectDisplayID { + unsafe { CGDisplayMirrorsDisplay(self.id) } + } + + /// Returns the primary display in a hardware mirroring set. + #[inline] + pub fn primary_display(&self) -> CGDirectDisplayID { + unsafe { CGDisplayPrimaryDisplay(self.id) } + } + + /// Returns the rotation angle of a display in degrees. + #[inline] + pub fn rotation(&self) -> f64 { + unsafe { CGDisplayRotation(self.id) } + } + + /// Returns the width and height of a display in millimeters. + #[inline] + pub fn screen_size(&self) -> CGSize { + unsafe { CGDisplayScreenSize(self.id) } + } + + /// Returns the serial number of a display monitor. + #[inline] + pub fn serial_number(&self) -> u32 { + unsafe { CGDisplaySerialNumber(self.id) } + } + + /// Returns the logical unit number of a display. + #[inline] + pub fn unit_number(&self) -> u32 { + unsafe { CGDisplayUnitNumber(self.id) } + } + + /// Returns the vendor number of the specified display's monitor. + #[inline] + pub fn vendor_number(&self) -> u32 { + unsafe { CGDisplayVendorNumber(self.id) } + } + + /// Returns the model number of a display monitor. + #[inline] + pub fn model_number(&self) -> u32 { + unsafe { CGDisplayModelNumber(self.id) } + } + + /// Returns the display height in pixel units. + #[inline] + pub fn pixels_high(&self) -> u64 { + unsafe { CGDisplayPixelsHigh(self.id) as u64 } + } + + /// Returns the display width in pixel units. + #[inline] + pub fn pixels_wide(&self) -> u64 { + unsafe { CGDisplayPixelsWide(self.id) as u64 } + } + + /// Provides a list of displays that are active (or drawable). + #[inline] + pub fn active_displays() -> Result, CGError> { + let count = CGDisplay::active_display_count()?; + let mut buf: Vec = vec![0; count as usize]; + let result = + unsafe { CGGetActiveDisplayList(count as u32, buf.as_mut_ptr(), ptr::null_mut()) }; + if result == 0 { + Ok(buf) + } else { + Err(result) + } + } + + /// Provides count of displays that are active (or drawable). + #[inline] + pub fn active_display_count() -> Result { + let mut count: u32 = 0; + let result = unsafe { CGGetActiveDisplayList(0, ptr::null_mut(), &mut count) }; + if result == 0 { + Ok(count as u32) + } else { + Err(result) + } + } + + /// Hides the mouse cursor, and increments the hide cursor count. + #[inline] + pub fn hide_cursor(&self) -> Result<(), CGError> { + let result = unsafe { CGDisplayHideCursor(self.id) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Decrements the hide cursor count, and shows the mouse cursor if the + /// count is 0. + #[inline] + pub fn show_cursor(&self) -> Result<(), CGError> { + let result = unsafe { CGDisplayShowCursor(self.id) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Moves the mouse cursor to a specified point relative to the display + /// origin (the upper-left corner of the display). + #[inline] + pub fn move_cursor_to_point(&self, point: CGPoint) -> Result<(), CGError> { + let result = unsafe { CGDisplayMoveCursorToPoint(self.id, point) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Moves the mouse cursor without generating events. + #[inline] + pub fn warp_mouse_cursor_position(point: CGPoint) -> Result<(), CGError> { + let result = unsafe { CGWarpMouseCursorPosition(point) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } + + /// Connects or disconnects the mouse and cursor while an application is + /// in the foreground. + #[inline] + pub fn associate_mouse_and_mouse_cursor_position(connected: bool) -> Result<(), CGError> { + let result = unsafe { CGAssociateMouseAndMouseCursorPosition(connected as boolean_t) }; + if result == 0 { + Ok(()) + } else { + Err(result) + } + } +} + +impl CGDisplayMode { + /// Returns all display modes for the specified display id. + pub fn all_display_modes( + display_id: CGDirectDisplayID, + options: CFDictionaryRef, + ) -> Option> { + let array_opt: Option = unsafe { + let array_ref = CGDisplayCopyAllDisplayModes(display_id, options); + if !array_ref.is_null() { + Some(CFArray::wrap_under_create_rule(array_ref)) + } else { + None + } + }; + match array_opt { + Some(modes) => { + let vec: Vec = modes + .into_iter() + .map(|value0| { + let x = *value0.deref() as *mut ::sys::CGDisplayMode; + unsafe { CGDisplayMode::from_ptr(x) } + }).collect(); + Some(vec) + } + None => None, + } + } + + /// Returns the height of the specified display mode. + #[inline] + pub fn height(&self) -> u64 { + unsafe { CGDisplayModeGetHeight(self.as_ptr()) as u64 } + } + + /// Returns the width of the specified display mode. + #[inline] + pub fn width(&self) -> u64 { + unsafe { CGDisplayModeGetWidth(self.as_ptr()) as u64 } + } + + /// Returns the pixel height of the specified display mode. + #[inline] + pub fn pixel_height(&self) -> u64 { + unsafe { CGDisplayModeGetPixelHeight(self.as_ptr()) as u64 } + } + + /// Returns the pixel width of the specified display mode. + #[inline] + pub fn pixel_width(&self) -> u64 { + unsafe { CGDisplayModeGetPixelWidth(self.as_ptr()) as u64 } + } + + #[inline] + pub fn refresh_rate(&self) -> f64 { + unsafe { CGDisplayModeGetRefreshRate(self.as_ptr()) } + } + + /// Returns the I/O Kit flags of the specified display mode. + #[inline] + pub fn io_flags(&self) -> u32 { + unsafe { CGDisplayModeGetIOFlags(self.as_ptr()) as u32 } + } + + /// Returns the pixel encoding of the specified display mode. + #[inline] + pub fn pixel_encoding(&self) -> CFString { + unsafe { CFString::wrap_under_create_rule(CGDisplayModeCopyPixelEncoding(self.as_ptr())) } + } + + /// Returns the number of bits per pixel of the specified display mode. + pub fn bit_depth(&self) -> usize { + let pixel_encoding = self.pixel_encoding().to_string(); + // my numerical representation for kIO16BitFloatPixels and kIO32bitFloatPixels + // are made up and possibly non-sensical + if pixel_encoding.eq_ignore_ascii_case(kIO32BitFloatPixels) { + 96 + } else if pixel_encoding.eq_ignore_ascii_case(kIO64BitDirectPixels) { + 64 + } else if pixel_encoding.eq_ignore_ascii_case(kIO16BitFloatPixels) { + 48 + } else if pixel_encoding.eq_ignore_ascii_case(IO32BitDirectPixels) { + 32 + } else if pixel_encoding.eq_ignore_ascii_case(kIO30BitDirectPixels) { + 30 + } else if pixel_encoding.eq_ignore_ascii_case(IO16BitDirectPixels) { + 16 + } else if pixel_encoding.eq_ignore_ascii_case(IO8BitIndexedPixels) { + 8 + }else{ + 0 + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern "C" { + pub static CGRectNull: CGRect; + pub static CGRectInfinite: CGRect; + + pub static kCGDisplayShowDuplicateLowResolutionModes: CFStringRef; + + pub fn CGDisplayModeRelease(mode: ::sys::CGDisplayModeRef); + + pub fn CGMainDisplayID() -> CGDirectDisplayID; + pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID; + pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID; + pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double; + pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize; + pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> u32; + pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> u32; + pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t; + pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> u32; + pub fn CGGetActiveDisplayList( + max_displays: u32, + active_displays: *mut CGDirectDisplayID, + display_count: *mut u32, + ) -> CGError; + pub fn CGGetDisplaysWithRect( + rect: CGRect, + max_displays: u32, + displays: *mut CGDirectDisplayID, + matching_display_count: *mut u32, + ) -> CGError; + pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> u32; + pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t; + pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t; + pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect; + pub fn CGDisplayCreateImage(display: CGDirectDisplayID) -> ::sys::CGImageRef; + + pub fn CGBeginDisplayConfiguration(config: *mut CGDisplayConfigRef) -> CGError; + pub fn CGCancelDisplayConfiguration(config: CGDisplayConfigRef) -> CGError; + pub fn CGCompleteDisplayConfiguration( + config: CGDisplayConfigRef, + option: CGConfigureOption, + ) -> CGError; + pub fn CGConfigureDisplayWithDisplayMode( + config: CGDisplayConfigRef, + display: CGDirectDisplayID, + mode: ::sys::CGDisplayModeRef, + options: CFDictionaryRef, + ) -> CGError; + pub fn CGConfigureDisplayMirrorOfDisplay( + config: CGDisplayConfigRef, + display: CGDirectDisplayID, + master: CGDirectDisplayID, + ) -> CGError; + pub fn CGConfigureDisplayOrigin( + config: CGDisplayConfigRef, + display: CGDirectDisplayID, + x: i32, + y: i32, + ) -> CGError; + + pub fn CGDisplayCopyDisplayMode(display: CGDirectDisplayID) -> ::sys::CGDisplayModeRef; + pub fn CGDisplayModeGetHeight(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetWidth(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetPixelHeight(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetPixelWidth(mode: ::sys::CGDisplayModeRef) -> libc::size_t; + pub fn CGDisplayModeGetRefreshRate(mode: ::sys::CGDisplayModeRef) -> libc::c_double; + pub fn CGDisplayModeGetIOFlags(mode: ::sys::CGDisplayModeRef) -> u32; + pub fn CGDisplayModeCopyPixelEncoding(mode: ::sys::CGDisplayModeRef) -> CFStringRef; + + pub fn CGDisplayCopyAllDisplayModes( + display: CGDirectDisplayID, + options: CFDictionaryRef, + ) -> CFArrayRef; + + // mouse stuff + pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError; + pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError; + pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError; + pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError; + pub fn CGAssociateMouseAndMouseCursorPosition(connected: boolean_t) -> CGError; + + // Window Services Reference + pub fn CGWindowListCopyWindowInfo( + option: CGWindowListOption, + relativeToWindow: CGWindowID, + ) -> CFArrayRef; + pub fn CGWindowListCreateImage( + screenBounds: CGRect, + listOptions: CGWindowListOption, + windowId: CGWindowID, + imageOptions: CGWindowImageOption, + ) -> ::sys::CGImageRef; + pub fn CGWindowListCreateImageFromArray( + screenBounds: CGRect, + windowArray: CFArrayRef, + imageOptions: CGWindowImageOption, + ) -> ::sys::CGImageRef; +} diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/event.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/event.rs new file mode 100644 index 0000000..f28e293 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/event.rs @@ -0,0 +1,669 @@ +#![allow(non_upper_case_globals)] + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID}; +use geometry::CGPoint; +use event_source::CGEventSource; + +use libc; + +use foreign_types::ForeignType; + +pub type CGEventField = u32; +pub type CGKeyCode = u16; +pub type CGScrollEventUnit = u32; + +bitflags! { + /// Flags for events + /// + /// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) + #[repr(C)] + pub struct CGEventFlags: u64 { + const CGEventFlagNull = 0; + + // Device-independent modifier key bits. + const CGEventFlagAlphaShift = 0x00010000; + const CGEventFlagShift = 0x00020000; + const CGEventFlagControl = 0x00040000; + const CGEventFlagAlternate = 0x00080000; + const CGEventFlagCommand = 0x00100000; + + // Special key identifiers. + const CGEventFlagHelp = 0x00400000; + const CGEventFlagSecondaryFn = 0x00800000; + + // Identifies key events from numeric keypad area on extended keyboards. + const CGEventFlagNumericPad = 0x00200000; + + // Indicates if mouse/pen movement events are not being coalesced + const CGEventFlagNonCoalesced = 0x00000100; + } +} + +/// Key codes for keys that are independent of keyboard layout. +/// +/// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.13.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h) +#[repr(C)] +pub struct KeyCode; +impl KeyCode { + pub const RETURN: CGKeyCode = 0x24; + pub const TAB: CGKeyCode = 0x30; + pub const SPACE: CGKeyCode = 0x31; + pub const DELETE: CGKeyCode = 0x33; + pub const ESCAPE: CGKeyCode = 0x35; + pub const COMMAND: CGKeyCode = 0x37; + pub const SHIFT: CGKeyCode = 0x38; + pub const CAPS_LOCK: CGKeyCode = 0x39; + pub const OPTION: CGKeyCode = 0x3A; + pub const CONTROL: CGKeyCode = 0x3B; + pub const RIGHT_COMMAND: CGKeyCode = 0x36; + pub const RIGHT_SHIFT: CGKeyCode = 0x3C; + pub const RIGHT_OPTION: CGKeyCode = 0x3D; + pub const RIGHT_CONTROL: CGKeyCode = 0x3E; + pub const FUNCTION: CGKeyCode = 0x3F; + pub const VOLUME_UP: CGKeyCode = 0x48; + pub const VOLUME_DOWN: CGKeyCode = 0x49; + pub const MUTE: CGKeyCode = 0x4A; + pub const F1: CGKeyCode = 0x7A; + pub const F2: CGKeyCode = 0x78; + pub const F3: CGKeyCode = 0x63; + pub const F4: CGKeyCode = 0x76; + pub const F5: CGKeyCode = 0x60; + pub const F6: CGKeyCode = 0x61; + pub const F7: CGKeyCode = 0x62; + pub const F8: CGKeyCode = 0x64; + pub const F9: CGKeyCode = 0x65; + pub const F10: CGKeyCode = 0x6D; + pub const F11: CGKeyCode = 0x67; + pub const F12: CGKeyCode = 0x6F; + pub const F13: CGKeyCode = 0x69; + pub const F14: CGKeyCode = 0x6B; + pub const F15: CGKeyCode = 0x71; + pub const F16: CGKeyCode = 0x6A; + pub const F17: CGKeyCode = 0x40; + pub const F18: CGKeyCode = 0x4F; + pub const F19: CGKeyCode = 0x50; + pub const F20: CGKeyCode = 0x5A; + pub const HELP: CGKeyCode = 0x72; + pub const HOME: CGKeyCode = 0x73; + pub const PAGE_UP: CGKeyCode = 0x74; + pub const FORWARD_DELETE: CGKeyCode = 0x75; + pub const END: CGKeyCode = 0x77; + pub const PAGE_DOWN: CGKeyCode = 0x79; + pub const LEFT_ARROW: CGKeyCode = 0x7B; + pub const RIGHT_ARROW: CGKeyCode = 0x7C; + pub const DOWN_ARROW: CGKeyCode = 0x7D; + pub const UP_ARROW: CGKeyCode = 0x7E; +} + +#[repr(C)] +pub struct ScrollEventUnit {} +impl ScrollEventUnit { + pub const PIXEL: CGScrollEventUnit = 0; + pub const LINE: CGScrollEventUnit = 1; +} + +/// Constants that specify the different types of input events. +/// +/// [Ref](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-700/IOHIDSystem/IOKit/hidsystem/IOLLEvent.h) +#[repr(u32)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventType { + Null = 0, + + // Mouse events. + LeftMouseDown = 1, + LeftMouseUp = 2, + RightMouseDown = 3, + RightMouseUp = 4, + MouseMoved = 5, + LeftMouseDragged = 6, + RightMouseDragged = 7, + + // Keyboard events. + KeyDown = 10, + KeyUp = 11, + FlagsChanged = 12, + + // Specialized control devices. + ScrollWheel = 22, + TabletPointer = 23, + TabletProximity = 24, + OtherMouseDown = 25, + OtherMouseUp = 26, + OtherMouseDragged = 27, + + // Out of band event types. These are delivered to the event tap callback + // to notify it of unusual conditions that disable the event tap. + TapDisabledByTimeout = 0xFFFFFFFE, + TapDisabledByUserInput = 0xFFFFFFFF, +} + +/// Constants used as keys to access specialized fields in low-level events. +/// +/// [Ref](https://developer.apple.com/documentation/coregraphics/cgeventfield) +pub struct EventField; +impl EventField { + /// Key to access an integer field that contains the mouse button event + /// number. Matching mouse-down and mouse-up events will have the same + /// event number. + pub const MOUSE_EVENT_NUMBER: CGEventField = 0; + + /// Key to access an integer field that contains the mouse button click + /// state. A click state of 1 represents a single click. A click state of + /// 2 represents a double-click. A click state of 3 represents a + /// triple-click. + pub const MOUSE_EVENT_CLICK_STATE: CGEventField = 1; + + /// Key to access a double field that contains the mouse button pressure. + /// The pressure value may range from 0 to 1, with 0 representing the + /// mouse being up. This value is commonly set by tablet pens mimicking a + /// mouse. + pub const MOUSE_EVENT_PRESSURE: CGEventField = 2; + + /// Key to access an integer field that contains the mouse button number. + pub const MOUSE_EVENT_BUTTON_NUMBER: CGEventField = 3; + + /// Key to access an integer field that contains the horizontal mouse + /// delta since the last mouse movement event. + pub const MOUSE_EVENT_DELTA_X: CGEventField = 4; + + /// Key to access an integer field that contains the vertical mouse delta + /// since the last mouse movement event. + pub const MOUSE_EVENT_DELTA_Y: CGEventField = 5; + + /// Key to access an integer field. The value is non-zero if the event + /// should be ignored by the Inkwell subsystem. + pub const MOUSE_EVENT_INSTANT_MOUSER: CGEventField = 6; + + /// Key to access an integer field that encodes the mouse event subtype as + /// a `kCFNumberIntType'. + pub const MOUSE_EVENT_SUB_TYPE: CGEventField = 7; + + /// Key to access an integer field, non-zero when this is an autorepeat of + /// a key-down, and zero otherwise. + pub const KEYBOARD_EVENT_AUTOREPEAT: CGEventField = 8; + + /// Key to access an integer field that contains the virtual keycode of the + /// key-down or key-up event. + pub const KEYBOARD_EVENT_KEYCODE: CGEventField = 9; + + /// Key to access an integer field that contains the keyboard type + /// identifier. + pub const KEYBOARD_EVENT_KEYBOARD_TYPE: CGEventField = 10; + + /// Key to access an integer field that contains scrolling data. This field + /// typically contains the change in vertical position since the last + /// scrolling event from a Mighty Mouse scroller or a single-wheel mouse + /// scroller. + pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_1: CGEventField = 11; + + /// Key to access an integer field that contains scrolling data. This field + /// typically contains the change in horizontal position since the last + /// scrolling event from a Mighty Mouse scroller. + pub const SCROLL_WHEEL_EVENT_DELTA_AXIS_2: CGEventField = 12; + + /// Key to access a field that contains scrolling data. The scrolling data + /// represents a line-based or pixel-based change in vertical position + /// since the last scrolling event from a Mighty Mouse scroller or a + /// single-wheel mouse scroller. The scrolling data uses a fixed-point + /// 16.16 signed integer format. If this key is passed to + /// `CGEventGetDoubleValueField', the fixed-point value is converted to a + /// double value. + pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_1: CGEventField = 93; + + /// Key to access a field that contains scrolling data. The scrolling data + /// represents a line-based or pixel-based change in horizontal position + /// since the last scrolling event from a Mighty Mouse scroller. The + /// scrolling data uses a fixed-point 16.16 signed integer format. If this + /// key is passed to `CGEventGetDoubleValueField', the fixed-point value is + /// converted to a double value. + pub const SCROLL_WHEEL_EVENT_FIXED_POINT_DELTA_AXIS_2: CGEventField = 94; + + /// Key to access an integer field that contains pixel-based scrolling + /// data. The scrolling data represents the change in vertical position + /// since the last scrolling event from a Mighty Mouse scroller or a + /// single-wheel mouse scroller. + pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1: CGEventField = 96; + + /// Key to access an integer field that contains pixel-based scrolling + /// data. The scrolling data represents the change in horizontal position + /// since the last scrolling event from a Mighty Mouse scroller. + pub const SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2: CGEventField = 97; + + /// Key to access an integer field that indicates whether the event should + /// be ignored by the Inkwell subsystem. If the value is non-zero, the + /// event should be ignored. + pub const SCROLL_WHEEL_EVENT_INSTANT_MOUSER: CGEventField = 14; + + /// Key to access an integer field that contains the absolute X coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_X: CGEventField = 15; + + /// Key to access an integer field that contains the absolute Y coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_Y: CGEventField = 16; + + /// Key to access an integer field that contains the absolute Z coordinate + /// in tablet space at full tablet resolution. + pub const TABLET_EVENT_POINT_Z: CGEventField = 17; + + /// Key to access an integer field that contains the tablet button state. + /// Bit 0 is the first button, and a set bit represents a closed or pressed + /// button. Up to 16 buttons are supported. + pub const TABLET_EVENT_POINT_BUTTONS: CGEventField = 18; + + /// Key to access a double field that contains the tablet pen pressure. A + /// value of 0.0 represents no pressure, and 1.0 represents maximum + /// pressure. + pub const TABLET_EVENT_POINT_PRESSURE: CGEventField = 19; + + /// Key to access a double field that contains the horizontal tablet pen + /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. + pub const TABLET_EVENT_TILT_X: CGEventField = 20; + + /// Key to access a double field that contains the vertical tablet pen + /// tilt. A value of 0 represents no tilt, and 1 represents maximum tilt. + pub const TABLET_EVENT_TILT_Y: CGEventField = 21; + + /// Key to access a double field that contains the tablet pen rotation. + pub const TABLET_EVENT_ROTATION: CGEventField = 22; + + /// Key to access a double field that contains the tangential pressure on + /// the device. A value of 0.0 represents no pressure, and 1.0 represents + /// maximum pressure. + pub const TABLET_EVENT_TANGENTIAL_PRESSURE: CGEventField = 23; + + /// Key to access an integer field that contains the system-assigned unique + /// device ID. + pub const TABLET_EVENT_DEVICE_ID: CGEventField = 24; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_1: CGEventField = 25; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_2: CGEventField = 26; + + /// Key to access an integer field that contains a vendor-specified value. + pub const TABLET_EVENT_VENDOR_3: CGEventField = 27; + + /// Key to access an integer field that contains the vendor-defined ID, + /// typically the USB vendor ID. + pub const TABLET_PROXIMITY_EVENT_VENDOR_ID: CGEventField = 28; + + /// Key to access an integer field that contains the vendor-defined tablet + /// ID, typically the USB product ID. + pub const TABLET_PROXIMITY_EVENT_TABLET_ID: CGEventField = 29; + + /// Key to access an integer field that contains the vendor-defined ID of + /// the pointing device. + pub const TABLET_PROXIMITY_EVENT_POINTER_ID: CGEventField = 30; + + /// Key to access an integer field that contains the system-assigned + /// device ID. + pub const TABLET_PROXIMITY_EVENT_DEVICE_ID: CGEventField = 31; + + /// Key to access an integer field that contains the system-assigned + /// unique tablet ID. + pub const TABLET_PROXIMITY_EVENT_SYSTEM_TABLET_ID: CGEventField = 32; + + /// Key to access an integer field that contains the vendor-assigned + /// pointer type. + pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_TYPE: CGEventField = 33; + + /// Key to access an integer field that contains the vendor-defined + /// pointer serial number. + pub const TABLET_PROXIMITY_EVENT_VENDOR_POINTER_SERIAL_NUMBER: CGEventField = 34; + + /// Key to access an integer field that contains the vendor-defined unique + /// ID. + pub const TABLET_PROXIMITY_EVENT_VENDOR_UNIQUE_ID: CGEventField = 35; + + /// Key to access an integer field that contains the device capabilities + /// mask. + pub const TABLET_PROXIMITY_EVENT_CAPABILITY_MASK: CGEventField = 36; + + /// Key to access an integer field that contains the pointer type. + pub const TABLET_PROXIMITY_EVENT_POINTER_TYPE: CGEventField = 37; + + /// Key to access an integer field that indicates whether the pen is in + /// proximity to the tablet. The value is non-zero if the pen is in + /// proximity to the tablet and zero when leaving the tablet. + pub const TABLET_PROXIMITY_EVENT_ENTER_PROXIMITY: CGEventField = 38; + + /// Key to access a field that contains the event target process serial + /// number. The value is a 64-bit value. + pub const EVENT_TARGET_PROCESS_SERIAL_NUMBER: CGEventField = 39; + + /// Key to access a field that contains the event target Unix process ID. + pub const EVENT_TARGET_UNIX_PROCESS_ID: CGEventField = 40; + + /// Key to access a field that contains the event source Unix process ID. + pub const EVENT_SOURCE_UNIX_PROCESS_ID: CGEventField = 41; + + /// Key to access a field that contains the event source user-supplied + /// data, up to 64 bits. + pub const EVENT_SOURCE_USER_DATA: CGEventField = 42; + + /// Key to access a field that contains the event source Unix effective UID. + pub const EVENT_SOURCE_USER_ID: CGEventField = 43; + + /// Key to access a field that contains the event source Unix effective + /// GID. + pub const EVENT_SOURCE_GROUP_ID: CGEventField = 44; + + /// Key to access a field that contains the event source state ID used to + /// create this event. + pub const EVENT_SOURCE_STATE_ID: CGEventField = 45; + + /// Key to access an integer field that indicates whether a scrolling event + /// contains continuous, pixel-based scrolling data. The value is non-zero + /// when the scrolling data is pixel-based and zero when the scrolling data + /// is line-based. + pub const SCROLL_WHEEL_EVENT_IS_CONTINUOUS: CGEventField = 88; + + /// Added in 10.5; made public in 10.7. + pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER: CGEventField = 91; + pub const MOUSE_EVENT_WINDOW_UNDER_MOUSE_POINTER_THAT_CAN_HANDLE_THIS_EVENT: CGEventField = 92; +} + +// Constants that specify buttons on a one, two, or three-button mouse. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGMouseButton { + Left, + Right, + Center, +} + +/// Possible tapping points for events. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum CGEventTapLocation { + HID, + Session, + AnnotatedSession, +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGEvent; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGEvent; + pub struct CGEventRef; +} + +impl CGEvent { + pub fn type_id() -> CFTypeID { + unsafe { + CGEventGetTypeID() + } + } + + pub fn new(source: CGEventSource) -> Result { + unsafe { + let event_ref = CGEventCreate(source.as_ptr()); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn new_keyboard_event( + source: CGEventSource, + keycode: CGKeyCode, + keydown: bool + ) -> Result { + unsafe { + let event_ref = CGEventCreateKeyboardEvent(source.as_ptr(), keycode, keydown); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn new_mouse_event( + source: CGEventSource, + mouse_type: CGEventType, + mouse_cursor_position: CGPoint, + mouse_button: CGMouseButton + ) -> Result { + unsafe { + let event_ref = CGEventCreateMouseEvent(source.as_ptr(), mouse_type, + mouse_cursor_position, mouse_button); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + #[cfg(feature = "highsierra")] + pub fn new_scroll_event( + source: CGEventSource, + units: CGScrollEventUnit, + wheel_count: u32, + wheel1: i32, + wheel2: i32, + wheel3: i32, + ) -> Result { + unsafe { + let event_ref = CGEventCreateScrollWheelEvent2( + source.as_ptr(), + units, + wheel_count, + wheel1, + wheel2, + wheel3, + ); + if !event_ref.is_null() { + Ok(Self::from_ptr(event_ref)) + } else { + Err(()) + } + } + } + + pub fn post(&self, tap_location: CGEventTapLocation) { + unsafe { + CGEventPost(tap_location, self.as_ptr()); + } + } + + pub fn location(&self) -> CGPoint { + unsafe { + CGEventGetLocation(self.as_ptr()) + } + } + + #[cfg(feature = "elcapitan")] + pub fn post_to_pid(&self, pid: libc::pid_t) { + unsafe { + CGEventPostToPid(pid, self.as_ptr()); + } + } + + pub fn set_flags(&self, flags: CGEventFlags) { + unsafe { + CGEventSetFlags(self.as_ptr(), flags); + } + } + + pub fn get_flags(&self) -> CGEventFlags { + unsafe { + CGEventGetFlags(self.as_ptr()) + } + } + + pub fn set_type(&self, event_type: CGEventType) { + unsafe { + CGEventSetType(self.as_ptr(), event_type); + } + } + + pub fn get_type(&self) -> CGEventType { + unsafe { + CGEventGetType(self.as_ptr()) + } + } + + pub fn set_string_from_utf16_unchecked(&self, buf: &[u16]) { + let buflen = buf.len() as libc::c_ulong; + unsafe { + CGEventKeyboardSetUnicodeString(self.as_ptr(), buflen, buf.as_ptr()); + } + } + + pub fn set_string(&self, string: &str) { + let buf: Vec = string.encode_utf16().collect(); + self.set_string_from_utf16_unchecked(&buf); + } + + pub fn get_integer_value_field(&self, field: CGEventField) -> i64 { + unsafe { CGEventGetIntegerValueField(self.as_ptr(), field) } + } + + pub fn set_integer_value_field(&self, field: CGEventField, value: i64) { + unsafe { CGEventSetIntegerValueField(self.as_ptr(), field, value) } + } + + pub fn get_double_value_field(&self, field: CGEventField) -> f64 { + unsafe { CGEventGetDoubleValueField(self.as_ptr(), field) } + } + + pub fn set_double_value_field(&self, field: CGEventField, value: f64) { + unsafe { CGEventSetDoubleValueField(self.as_ptr(), field, value) } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + /// Return the type identifier for the opaque type `CGEventRef'. + fn CGEventGetTypeID() -> CFTypeID; + + /// Return a new event using the event source `source'. If `source' is NULL, + /// the default source is used. + fn CGEventCreate(source: ::sys::CGEventSourceRef) -> ::sys::CGEventRef; + + /// Return a new keyboard event. + /// + /// The event source may be taken from another event, or may be NULL. Based + /// on the virtual key code values entered, the appropriate key down, key up, + /// or flags changed events are generated. + /// + /// All keystrokes needed to generate a character must be entered, including + /// SHIFT, CONTROL, OPTION, and COMMAND keys. For example, to produce a 'Z', + /// the SHIFT key must be down, the 'z' key must go down, and then the SHIFT + /// and 'z' key must be released: + fn CGEventCreateKeyboardEvent(source: ::sys::CGEventSourceRef, keycode: CGKeyCode, + keydown: bool) -> ::sys::CGEventRef; + + /// Return a new mouse event. + /// + /// The event source may be taken from another event, or may be NULL. + /// `mouseType' should be one of the mouse event types. `mouseCursorPosition' + /// should be the position of the mouse cursor in global coordinates. + /// `mouseButton' should be the button that's changing state; `mouseButton' + /// is ignored unless `mouseType' is one of `kCGEventOtherMouseDown', + /// `kCGEventOtherMouseDragged', or `kCGEventOtherMouseUp'. + /// + /// The current implementation of the event system supports a maximum of + /// thirty-two buttons. Mouse button 0 is the primary button on the mouse. + /// Mouse button 1 is the secondary mouse button (right). Mouse button 2 is + /// the center button, and the remaining buttons are in USB device order. + fn CGEventCreateMouseEvent(source: ::sys::CGEventSourceRef, mouseType: CGEventType, + mouseCursorPosition: CGPoint, mouseButton: CGMouseButton) -> ::sys::CGEventRef; + + /// A non-variadic variant version of CGEventCreateScrollWheelEvent. + /// + /// Returns a new Quartz scrolling event. + /// + /// This function allows you to create a scrolling event and customize the + /// event before posting it to the event system. + #[cfg(feature = "highsierra")] + fn CGEventCreateScrollWheelEvent2( + source: ::sys::CGEventSourceRef, + units: CGScrollEventUnit, + wheelCount: u32, + wheel1: i32, + wheel2: i32, + wheel3: i32, + ) -> ::sys::CGEventRef; + + /// Post an event into the event stream at a specified location. + /// + /// This function posts the specified event immediately before any event taps + /// instantiated for that location, and the event passes through any such + /// taps. + fn CGEventPost(tapLocation: CGEventTapLocation, event: ::sys::CGEventRef); + + #[cfg(feature = "elcapitan")] + /// Post an event to a specified process ID + fn CGEventPostToPid(pid: libc::pid_t, event: ::sys::CGEventRef); + + /// Set the event flags of an event. + fn CGEventSetFlags(event: ::sys::CGEventRef, flags: CGEventFlags); + + /// Return the event flags of an event. + fn CGEventGetFlags(event: ::sys::CGEventRef) -> CGEventFlags; + + /// Return the location of an event in global display coordinates. + /// CGPointZero is returned if event is not a valid ::sys::CGEventRef. + fn CGEventGetLocation(event: ::sys::CGEventRef) -> CGPoint; + + /// Set the event type of an event. + fn CGEventSetType(event: ::sys::CGEventRef, eventType: CGEventType); + + /// Return the event type of an event (left mouse down, for example). + fn CGEventGetType(event: ::sys::CGEventRef) -> CGEventType; + + /// Set the Unicode string associated with a keyboard event. + /// + /// By default, the system translates the virtual key code in a keyboard + /// event into a Unicode string based on the keyboard ID in the event + /// source. This function allows you to manually override this string. + /// Note that application frameworks may ignore the Unicode string in a + /// keyboard event and do their own translation based on the virtual + /// keycode and perceived event state. + fn CGEventKeyboardSetUnicodeString(event: ::sys::CGEventRef, + length: libc::c_ulong, + string: *const u16); + + /// Return the integer value of a field in an event. + fn CGEventGetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField) -> i64; + + /// Set the integer value of a field in an event. + /// + /// Before calling this function, the event type must be set using a typed + /// event creation function such as `CGEventCreateMouseEvent', or by + /// calling `CGEventSetType'. + /// + /// If you are creating a mouse event generated by a tablet, call this + /// function and specify the field `kCGMouseEventSubtype' with a value of + /// `kCGEventMouseSubtypeTabletPoint' or + /// `kCGEventMouseSubtypeTabletProximity' before setting other parameters. + fn CGEventSetIntegerValueField(event: ::sys::CGEventRef, field: CGEventField, value: i64); + + /// Return the floating-point value of a field in an event. + /// + /// In cases where the field value is represented within the event by a fixed + /// point number or an integer, the result is scaled to the appropriate range + /// as part of creating the floating-point representation. + fn CGEventGetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField) -> f64; + + /// Set the floating-point value of a field in an event. + /// + /// Before calling this function, the event type must be set using a typed + /// event creation function such as `CGEventCreateMouseEvent', or by calling + /// `CGEventSetType'. + /// + /// In cases where the field’s value is represented within the event by a + /// fixed point number or integer, the value parameter is scaled as needed + /// and converted to the appropriate type. + fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64); +} diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/event_source.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/event_source.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/event_source.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/event_source.rs diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/font.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/font.rs new file mode 100644 index 0000000..11ebe30 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/font.rs @@ -0,0 +1,156 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core_foundation::base::{CFRelease, CFRetain, CFTypeID, TCFType}; +use core_foundation::array::{CFArray, CFArrayRef}; +use core_foundation::data::{CFData, CFDataRef}; +use core_foundation::number::CFNumber; +use core_foundation::string::{CFString, CFStringRef}; +use core_foundation::dictionary::{CFDictionary, CFDictionaryRef}; +use data_provider::CGDataProvider; +use geometry::CGRect; + +use foreign_types::ForeignType; + +use libc::{c_int, size_t}; + +pub use core_graphics_types::base::CGGlyph; + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGFont; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGFont; + pub struct CGFontRef; +} + +unsafe impl Send for CGFont {} +unsafe impl Sync for CGFont {} + +impl CGFont { + pub fn type_id() -> CFTypeID { + unsafe { + CGFontGetTypeID() + } + } + + pub fn from_data_provider(provider: CGDataProvider) -> Result { + unsafe { + let font_ref = CGFontCreateWithDataProvider(provider.as_ptr()); + if !font_ref.is_null() { + Ok(CGFont::from_ptr(font_ref)) + } else { + Err(()) + } + } + } + + pub fn from_name(name: &CFString) -> Result { + unsafe { + let font_ref = CGFontCreateWithFontName(name.as_concrete_TypeRef()); + if !font_ref.is_null() { + Ok(CGFont::from_ptr(font_ref)) + } else { + Err(()) + } + } + } + + pub fn create_copy_from_variations(&self, vars: &CFDictionary) -> Result { + unsafe { + let font_ref = CGFontCreateCopyWithVariations(self.as_ptr(), + vars.as_concrete_TypeRef()); + if !font_ref.is_null() { + Ok(CGFont::from_ptr(font_ref)) + } else { + Err(()) + } + } + } + + pub fn postscript_name(&self) -> CFString { + unsafe { + let string_ref = CGFontCopyPostScriptName(self.as_ptr()); + TCFType::wrap_under_create_rule(string_ref) + } + } + + pub fn get_glyph_b_boxes(&self, glyphs: &[CGGlyph], bboxes: &mut [CGRect]) -> bool { + unsafe { + assert!(bboxes.len() >= glyphs.len()); + CGFontGetGlyphBBoxes(self.as_ptr(), + glyphs.as_ptr(), + glyphs.len(), + bboxes.as_mut_ptr()) + } + } + + pub fn get_glyph_advances(&self, glyphs: &[CGGlyph], advances: &mut [c_int]) -> bool { + unsafe { + assert!(advances.len() >= glyphs.len()); + CGFontGetGlyphAdvances(self.as_ptr(), + glyphs.as_ptr(), + glyphs.len(), + advances.as_mut_ptr()) + } + } + + pub fn get_units_per_em(&self) -> c_int { + unsafe { + CGFontGetUnitsPerEm(self.as_ptr()) + } + } + + pub fn copy_table_tags(&self) -> CFArray { + unsafe { + TCFType::wrap_under_create_rule(CGFontCopyTableTags(self.as_ptr())) + } + } + + pub fn copy_table_for_tag(&self, tag: u32) -> Option { + let data_ref = unsafe { CGFontCopyTableForTag(self.as_ptr(), tag) }; + if !data_ref.is_null() { + Some(unsafe { TCFType::wrap_under_create_rule(data_ref) }) + } else { + None + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + // TODO: basically nothing has bindings (even commented-out) besides what we use. + fn CGFontCreateWithDataProvider(provider: ::sys::CGDataProviderRef) -> ::sys::CGFontRef; + fn CGFontCreateWithFontName(name: CFStringRef) -> ::sys::CGFontRef; + fn CGFontCreateCopyWithVariations(font: ::sys::CGFontRef, vars: CFDictionaryRef) -> ::sys::CGFontRef; + fn CGFontGetTypeID() -> CFTypeID; + + fn CGFontCopyPostScriptName(font: ::sys::CGFontRef) -> CFStringRef; + + // These do the same thing as CFRetain/CFRelease, except + // gracefully handle a NULL argument. We don't use them. + //fn CGFontRetain(font: ::sys::CGFontRef); + //fn CGFontRelease(font: ::sys::CGFontRef); + + fn CGFontGetGlyphBBoxes(font: ::sys::CGFontRef, + glyphs: *const CGGlyph, + count: size_t, + bboxes: *mut CGRect) + -> bool; + fn CGFontGetGlyphAdvances(font: ::sys::CGFontRef, + glyphs: *const CGGlyph, + count: size_t, + advances: *mut c_int) + -> bool; + fn CGFontGetUnitsPerEm(font: ::sys::CGFontRef) -> c_int; + + fn CGFontCopyTableTags(font: ::sys::CGFontRef) -> CFArrayRef; + fn CGFontCopyTableForTag(font: ::sys::CGFontRef, tag: u32) -> CFDataRef; +} diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/geometry.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/geometry.rs new file mode 100644 index 0000000..fd4dc97 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/geometry.rs @@ -0,0 +1,10 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use core_graphics_types::geometry::*; \ No newline at end of file diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/gradient.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/gradient.rs new file mode 100644 index 0000000..5c6cde8 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/gradient.rs @@ -0,0 +1,62 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use base::CGFloat; +use color::CGColor; +use color_space::CGColorSpace; + +use core_foundation::array::{ CFArray, CFArrayRef }; +use core_foundation::base::{CFRelease, CFRetain, TCFType}; +use foreign_types::ForeignType; + +use libc::size_t; + +bitflags! { + #[repr(C)] + pub struct CGGradientDrawingOptions: u32 { + const CGGradientDrawsBeforeStartLocation = (1 << 0); + const CGGradientDrawsAfterEndLocation = (1 << 1); + } +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGGradient; + fn drop = |p| CFRelease(p as *mut _); + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGGradient; + pub struct CGGradientRef; +} + +impl CGGradient { + pub fn create_with_color_components(color_space: &CGColorSpace, components: &[CGFloat], locations: &[CGFloat], count: usize) -> CGGradient { + unsafe { + let result = CGGradientCreateWithColorComponents(color_space.as_ptr(), components.as_ptr(), locations.as_ptr(), count); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn create_with_colors(color_space: &CGColorSpace, colors: &CFArray, locations: &[CGFloat]) -> CGGradient { + unsafe { + let result = CGGradientCreateWithColors(color_space.as_ptr(), colors.as_concrete_TypeRef(), locations.as_ptr()); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGGradientCreateWithColorComponents(color_space: ::sys::CGColorSpaceRef, components: *const CGFloat, locations: *const CGFloat, count: size_t) -> ::sys::CGGradientRef; + fn CGGradientCreateWithColors(color_space: ::sys::CGColorSpaceRef, colors: CFArrayRef, locations: *const CGFloat) -> ::sys::CGGradientRef; +} + diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/image.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/image.rs new file mode 100644 index 0000000..f1b9509 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/image.rs @@ -0,0 +1,165 @@ +use std::ptr; + +use base::CGFloat; +use core_foundation::base::{CFRetain, CFTypeID}; +use core_foundation::data::CFData; +use color_space::CGColorSpace; +use data_provider::{CGDataProviderRef, CGDataProvider}; +use geometry::CGRect; +use libc::size_t; +use foreign_types::{ForeignType, ForeignTypeRef}; + +#[repr(C)] +pub enum CGImageAlphaInfo { + CGImageAlphaNone, /* For example, RGB. */ + CGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ + CGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ + CGImageAlphaLast, /* For example, non-premultiplied RGBA */ + CGImageAlphaFirst, /* For example, non-premultiplied ARGB */ + CGImageAlphaNoneSkipLast, /* For example, RBGX. */ + CGImageAlphaNoneSkipFirst, /* For example, XRBG. */ + CGImageAlphaOnly /* No color data, alpha data only */ +} + +#[repr(C)] +pub enum CGImageByteOrderInfo { + CGImageByteOrderMask = 0x7000, + CGImageByteOrder16Little = 1 << 12, + CGImageByteOrder32Little = 2 << 12, + CGImageByteOrder16Big = 3 << 12, + CGImageByteOrder32Big = 4 << 12 +} + +foreign_type! { + #[doc(hidden)] + type CType = ::sys::CGImage; + fn drop = CGImageRelease; + fn clone = |p| CFRetain(p as *const _) as *mut _; + pub struct CGImage; + pub struct CGImageRef; +} + +impl CGImage { + pub fn new(width: size_t, + height: size_t, + bits_per_component: size_t, + bits_per_pixel: size_t, + bytes_per_row: size_t, + colorspace: &CGColorSpace, + bitmap_info: u32, + provider: &CGDataProvider, + should_interpolate: bool, + rendering_intent: u32) + -> Self { + unsafe { + let result = CGImageCreate(width, + height, + bits_per_component, + bits_per_pixel, + bytes_per_row, + colorspace.as_ptr(), + bitmap_info, + provider.as_ptr(), + ptr::null_mut(), + should_interpolate, + rendering_intent); + assert!(!result.is_null()); + Self::from_ptr(result) + } + } + + pub fn type_id() -> CFTypeID { + unsafe { + CGImageGetTypeID() + } + } +} + +impl CGImageRef { + pub fn width(&self) -> size_t { + unsafe { + CGImageGetWidth(self.as_ptr()) + } + } + + pub fn height(&self) -> size_t { + unsafe { + CGImageGetHeight(self.as_ptr()) + } + } + + pub fn bits_per_component(&self) -> size_t { + unsafe { + CGImageGetBitsPerComponent(self.as_ptr()) + } + } + + pub fn bits_per_pixel(&self) -> size_t { + unsafe { + CGImageGetBitsPerPixel(self.as_ptr()) + } + } + + pub fn bytes_per_row(&self) -> size_t { + unsafe { + CGImageGetBytesPerRow(self.as_ptr()) + } + } + + pub fn color_space(&self) -> CGColorSpace { + unsafe { + let cs = CGImageGetColorSpace(self.as_ptr()); + CFRetain(cs as *mut _); + CGColorSpace::from_ptr(cs) + } + } + + /// Returns the raw image bytes wrapped in `CFData`. Note, the returned `CFData` owns the + /// underlying buffer. + pub fn data(&self) -> CFData { + let data_provider = unsafe { + CGDataProviderRef::from_ptr(CGImageGetDataProvider(self.as_ptr())) + }; + data_provider.copy_data() + } + + /// Returns a cropped image. If the `rect` specifies a rectangle which lies outside of the + /// image bounds, the `None` is returned. + pub fn cropped(&self, rect: CGRect) -> Option { + let image_ptr = unsafe { CGImageCreateWithImageInRect(self.as_ptr(), rect) }; + if !image_ptr.is_null() { + Some(unsafe { CGImage::from_ptr(image_ptr) }) + } else { + None + } + } +} + +#[link(name = "CoreGraphics", kind = "framework")] +extern { + fn CGImageGetTypeID() -> CFTypeID; + fn CGImageGetWidth(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetHeight(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBitsPerComponent(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBitsPerPixel(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetBytesPerRow(image: ::sys::CGImageRef) -> size_t; + fn CGImageGetColorSpace(image: ::sys::CGImageRef) -> ::sys::CGColorSpaceRef; + fn CGImageGetDataProvider(image: ::sys::CGImageRef) -> ::sys::CGDataProviderRef; + fn CGImageRelease(image: ::sys::CGImageRef); + fn CGImageCreate(width: size_t, + height: size_t, + bitsPerComponent: size_t, + bitsPerPixel: size_t, + bytesPerRow: size_t, + space: ::sys::CGColorSpaceRef, + bitmapInfo: u32, + provider: ::sys::CGDataProviderRef, + decode: *const CGFloat, + shouldInterpolate: bool, + intent: u32) + -> ::sys::CGImageRef; + fn CGImageCreateWithImageInRect(image: ::sys::CGImageRef, rect: CGRect) -> ::sys::CGImageRef; + + //fn CGImageGetAlphaInfo(image: ::sys::CGImageRef) -> CGImageAlphaInfo; + //fn CGImageCreateCopyWithColorSpace(image: ::sys::CGImageRef, space: ::sys::CGColorSpaceRef) -> ::sys::CGImageRef +} diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/lib.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/lib.rs new file mode 100644 index 0000000..5238774 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/lib.rs @@ -0,0 +1,43 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate libc; + +#[macro_use] +extern crate core_foundation; + +#[macro_use] +extern crate bitflags; + +#[macro_use] +extern crate foreign_types; + +extern crate core_graphics_types; + +pub mod base; +pub mod color; +pub mod color_space; +pub mod context; +pub mod data_provider; +#[cfg(target_os = "macos")] +pub mod display; +#[cfg(target_os = "macos")] +pub mod event; +#[cfg(target_os = "macos")] +pub mod event_source; +pub mod font; +pub mod geometry; +pub mod gradient; +#[cfg(target_os = "macos")] +pub mod window; +#[cfg(target_os = "macos")] +pub mod private; +pub mod image; +pub mod path; +pub mod sys; diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/path.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/path.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/path.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/path.rs diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/private.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/private.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/private.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/private.rs diff --git a/third_party/cargo/vendor/core-graphics-0.22.2/src/sys.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/sys.rs new file mode 100644 index 0000000..2ae5261 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-0.22.2/src/sys.rs @@ -0,0 +1,42 @@ +use std::os::raw::c_void; + +pub enum CGImage {} +pub type CGImageRef = *mut CGImage; + +#[repr(C)] +pub struct __CGColor(c_void); + +pub type CGColorRef = *const __CGColor; + +pub enum CGColorSpace {} +pub type CGColorSpaceRef = *mut CGColorSpace; + +pub enum CGPath {} +pub type CGPathRef = *mut CGPath; + +pub enum CGDataProvider {} +pub type CGDataProviderRef = *mut CGDataProvider; + +pub enum CGFont {} +pub type CGFontRef = *mut CGFont; + +pub enum CGContext {} +pub type CGContextRef = *mut CGContext; + +pub enum CGGradient {} +pub type CGGradientRef = *mut CGGradient; + +#[cfg(target_os = "macos")] +mod macos { + pub enum CGEvent {} + pub type CGEventRef = *mut CGEvent; + + pub enum CGEventSource {} + pub type CGEventSourceRef = *mut CGEventSource; + + pub enum CGDisplayMode {} + pub type CGDisplayModeRef = *mut CGDisplayMode; +} + +#[cfg(target_os = "macos")] +pub use self::macos::*; diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/src/window.rs b/third_party/cargo/vendor/core-graphics-0.22.2/src/window.rs similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/src/window.rs rename to third_party/cargo/vendor/core-graphics-0.22.2/src/window.rs diff --git a/third_party/cargo/vendor/core-graphics-types-0.1.1/.cargo-checksum.json b/third_party/cargo/vendor/core-graphics-types-0.1.1/.cargo-checksum.json new file mode 100644 index 0000000..31da816 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-types-0.1.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"e2e38d84cf514ad088ebc1909123ef4f707db6855528f938eb57d1e06c5a23ef","src/base.rs":"3764010f0c416db49be8a9e191fffb6848e8287edbdd5b12972613e301720ded","src/geometry.rs":"b94e50a16b8540dc6f37bfe4b1549ac68974cd6ba6c0bbd9209559f8a46d86eb","src/lib.rs":"31700ac9508fd32005bafd1c12a86a6803d198e9b1a71166a7391e642c091cd1"},"package":"3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"} \ No newline at end of file diff --git a/third_party/cargo/vendor/core-graphics-types-0.1.1/BUILD.bazel b/third_party/cargo/vendor/core-graphics-types-0.1.1/BUILD.bazel new file mode 100644 index 0000000..88afa6d --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-types-0.1.1/BUILD.bazel @@ -0,0 +1,57 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "core_graphics_types", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.1.1", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/bitflags-1.2.1:bitflags", + "//third_party/cargo/vendor/core-foundation-0.9.1:core_foundation", + "//third_party/cargo/vendor/foreign-types-0.3.2:foreign_types", + "//third_party/cargo/vendor/libc-0.2.82:libc", + ], +) diff --git a/third_party/cargo/vendor/core-graphics-types-0.1.1/Cargo.toml b/third_party/cargo/vendor/core-graphics-types-0.1.1/Cargo.toml new file mode 100644 index 0000000..fbc4836 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-types-0.1.1/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-graphics-types" +version = "0.1.1" +authors = ["The Servo Project Developers"] +description = "Bindings for some fundamental Core Graphics types" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[package.metadata.docs.rs] +default-target = "x86_64-apple-darwin" +[dependencies.bitflags] +version = "1.0" + +[dependencies.core-foundation] +version = "0.9" + +[dependencies.foreign-types] +version = "0.3.0" + +[dependencies.libc] +version = "0.2" diff --git a/third_party/cargo/vendor/core-graphics-types-0.1.1/src/base.rs b/third_party/cargo/vendor/core-graphics-types-0.1.1/src/base.rs new file mode 100644 index 0000000..d5efc3b --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-types-0.1.1/src/base.rs @@ -0,0 +1,32 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this file defines CGFloat, as well as stubbed data types. + +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +use libc; + +#[cfg(any(target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64"))] +pub type boolean_t = libc::c_int; +#[cfg(target_arch = "x86_64")] +pub type boolean_t = libc::c_uint; + +#[cfg(target_pointer_width = "64")] +pub type CGFloat = libc::c_double; +#[cfg(not(target_pointer_width = "64"))] +pub type CGFloat = libc::c_float; + +pub type CGError = libc::int32_t; + +pub type CGGlyph = libc::c_ushort; + diff --git a/third_party/cargo/vendor/core-graphics-types-0.1.1/src/geometry.rs b/third_party/cargo/vendor/core-graphics-types-0.1.1/src/geometry.rs new file mode 100644 index 0000000..906c605 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-types-0.1.1/src/geometry.rs @@ -0,0 +1,195 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use base::CGFloat; +use core_foundation::base::TCFType; +use core_foundation::dictionary::CFDictionary; + +pub const CG_ZERO_POINT: CGPoint = CGPoint { + x: 0.0, + y: 0.0, +}; + +pub const CG_ZERO_SIZE: CGSize = CGSize { + width: 0.0, + height: 0.0, +}; + +pub const CG_ZERO_RECT: CGRect = CGRect { + origin: CG_ZERO_POINT, + size: CG_ZERO_SIZE, +}; + +pub const CG_AFFINE_TRANSFORM_IDENTITY: CGAffineTransform = CGAffineTransform { + a: 1.0, b: 0.0, + c: 0.0, d: 1.0, + tx: 0.0, ty: 0.0, +}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGSize { + pub width: CGFloat, + pub height: CGFloat, +} + +impl CGSize { + #[inline] + pub fn new(width: CGFloat, height: CGFloat) -> CGSize { + CGSize { + width: width, + height: height, + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGSize { + unsafe { + ffi::CGSizeApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGPoint { + pub x: CGFloat, + pub y: CGFloat, +} + +impl CGPoint { + #[inline] + pub fn new(x: CGFloat, y: CGFloat) -> CGPoint { + CGPoint { + x: x, + y: y, + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGPoint { + unsafe { + ffi::CGPointApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGRect { + pub origin: CGPoint, + pub size: CGSize +} + +impl CGRect { + #[inline] + pub fn new(origin: &CGPoint, size: &CGSize) -> CGRect { + CGRect { + origin: *origin, + size: *size, + } + } + + #[inline] + pub fn inset(&self, size: &CGSize) -> CGRect { + unsafe { + ffi::CGRectInset(*self, size.width, size.height) + } + } + + #[inline] + pub fn from_dict_representation(dict: &CFDictionary) -> Option { + let mut rect = CGRect::new(&CGPoint::new(0., 0.), &CGSize::new(0., 0.)); + let result = unsafe { + ffi::CGRectMakeWithDictionaryRepresentation(dict.as_concrete_TypeRef(), &mut rect) + }; + if result == 0 { + None + } else { + Some(rect) + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + unsafe { + // I use one, as it seems that `YES` is not available from this crate. + ffi::CGRectIsEmpty(*self) == 1 + } + } + + #[inline] + pub fn is_intersects(&self, other: &CGRect) -> bool { + unsafe { + // I use one, as it seems that `YES` is not available from this crate. + ffi::CGRectIntersectsRect(*self, *other) == 1 + } + } + + #[inline] + pub fn apply_transform(&self, t: &CGAffineTransform) -> CGRect { + unsafe { + ffi::CGRectApplyAffineTransform(*self, *t) + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct CGAffineTransform { + pub a: CGFloat, + pub b: CGFloat, + pub c: CGFloat, + pub d: CGFloat, + pub tx: CGFloat, + pub ty: CGFloat, +} + +impl CGAffineTransform { + #[inline] + pub fn new( + a: CGFloat, + b: CGFloat, + c: CGFloat, + d: CGFloat, + tx: CGFloat, + ty: CGFloat, + ) -> CGAffineTransform { + CGAffineTransform { a, b, c, d, tx, ty } + } + + #[inline] + pub fn invert(&self) -> CGAffineTransform { + unsafe { + ffi::CGAffineTransformInvert(*self) + } + } +} + +mod ffi { + use base::{CGFloat, boolean_t}; + use geometry::{CGAffineTransform, CGPoint, CGRect, CGSize}; + use core_foundation::dictionary::CFDictionaryRef; + + #[link(name = "CoreGraphics", kind = "framework")] + extern { + pub fn CGRectInset(rect: CGRect, dx: CGFloat, dy: CGFloat) -> CGRect; + pub fn CGRectMakeWithDictionaryRepresentation(dict: CFDictionaryRef, + rect: *mut CGRect) -> boolean_t; + pub fn CGRectIsEmpty(rect: CGRect) -> boolean_t; + pub fn CGRectIntersectsRect(rect1: CGRect, rect2: CGRect) -> boolean_t; + + pub fn CGAffineTransformInvert(t: CGAffineTransform) -> CGAffineTransform; + + pub fn CGPointApplyAffineTransform(point: CGPoint, t: CGAffineTransform) -> CGPoint; + pub fn CGRectApplyAffineTransform(rect: CGRect, t: CGAffineTransform) -> CGRect; + pub fn CGSizeApplyAffineTransform(size: CGSize, t: CGAffineTransform) -> CGSize; + } +} + diff --git a/third_party/cargo/vendor/core-graphics-types-0.1.1/src/lib.rs b/third_party/cargo/vendor/core-graphics-types-0.1.1/src/lib.rs new file mode 100644 index 0000000..f34bf01 --- /dev/null +++ b/third_party/cargo/vendor/core-graphics-types-0.1.1/src/lib.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate libc; +extern crate core_foundation; + +pub mod base; +pub mod geometry; diff --git a/third_party/cargo/vendor/core-video-sys-0.1.4/BUILD.bazel b/third_party/cargo/vendor/core-video-sys-0.1.4/BUILD.bazel index 1a3b58a..de660a2 100644 --- a/third_party/cargo/vendor/core-video-sys-0.1.4/BUILD.bazel +++ b/third_party/cargo/vendor/core-video-sys-0.1.4/BUILD.bazel @@ -54,8 +54,8 @@ rust_library( deps = [ "//third_party/cargo/vendor/cfg-if-0.1.10:cfg_if", "//third_party/cargo/vendor/core-foundation-sys-0.7.0:core_foundation_sys", - "//third_party/cargo/vendor/core-graphics-0.19.0:core_graphics", - "//third_party/cargo/vendor/libc-0.2.71:libc", + "//third_party/cargo/vendor/core-graphics-0.19.2:core_graphics", + "//third_party/cargo/vendor/libc-0.2.82:libc", "//third_party/cargo/vendor/objc-0.2.7:objc", ], ) diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/.cargo-checksum.json b/third_party/cargo/vendor/crc32fast-1.2.0/.cargo-checksum.json deleted file mode 100644 index 7c08c96..0000000 --- a/third_party/cargo/vendor/crc32fast-1.2.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"c85c0241394119d8887c5e5624aba9a1a1fd21578f1a1e3f2a0d50d95d752cff","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"61d383b05b87d78f94d2937e2580cce47226d17823c0430fbcad09596537efcf","README.md":"c0891c7ff327441bf16da593b0e721951f9f6d10bb26f9356aba6a7b0b0c4575","benches/bench.rs":"9a45a7ebc8fecf7f9976bea0e3c00c13731c0b3566536b0bc83788986e801770","build.rs":"4ccc50c3da67eb27f0b622440d2b7aee2f73fa9c71884571f3c041122231d105","src/baseline.rs":"bbe8fe49ceccbf9749052fa9c2756cf95f0fc79a063e5d3b509e3600283464ea","src/combine.rs":"7147fc4002190d36d253ea5e194e0419035b087304bcb17887efe09a8a198815","src/lib.rs":"25c55822d7fd53ff1ff0769bcffbdbcade00d45ac042a541b7189c2e94b91ee7","src/specialized/aarch64.rs":"cc8097e68f1269cee32aa856b4f7e4ba7b7472df6c2f4cecd600d292a838fe83","src/specialized/mod.rs":"bc92450e8522e9df202b346b3a209153cbb0d6587804cbfd2b947fda0f190ed6","src/specialized/pclmulqdq.rs":"6ace803b42ff70a571fd8b5f3f7c2d5a836873ce28759381c2882319b8edba70","src/table.rs":"3201c520d97c5e2cf80b8a03d72fa2e3f1270bbdf93c2fbf85498a8ea39bc64b"},"package":"ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/BUILD.bazel b/third_party/cargo/vendor/crc32fast-1.2.0/BUILD.bazel deleted file mode 100644 index 752f39a..0000000 --- a/third_party/cargo/vendor/crc32fast-1.2.0/BUILD.bazel +++ /dev/null @@ -1,60 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -# Unsupported target "bench" with type "bench" omitted - -# Unsupported target "build-script-build" with type "custom-build" omitted - -rust_library( - name = "crc32fast", - srcs = glob(["**/*.rs"]), - crate_features = [ - "default", - "std", - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "1.2.0", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/cfg-if-0.1.10:cfg_if", - ], -) diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/Cargo.toml b/third_party/cargo/vendor/crc32fast-1.2.0/Cargo.toml deleted file mode 100644 index ca8bbcc..0000000 --- a/third_party/cargo/vendor/crc32fast-1.2.0/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "crc32fast" -version = "1.2.0" -authors = ["Sam Rijs ", "Alex Crichton "] -description = "Fast, SIMD-accelerated CRC32 (IEEE) checksum computation" -readme = "README.md" -keywords = ["checksum", "crc", "crc32", "simd", "fast"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/srijs/rust-crc32fast" - -[[bench]] -name = "bench" -harness = false -[dependencies.cfg-if] -version = "0.1" -[dev-dependencies.bencher] -version = "0.1" - -[dev-dependencies.quickcheck] -version = "0.6" -default-features = false - -[dev-dependencies.rand] -version = "0.4" - -[features] -default = ["std"] -nightly = [] -std = [] diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/README.md b/third_party/cargo/vendor/crc32fast-1.2.0/README.md deleted file mode 100644 index 4267dfa..0000000 --- a/third_party/cargo/vendor/crc32fast-1.2.0/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# crc32fast [![Build Status][travis-img]][travis] [![Crates.io][crates-img]][crates] [![Documentation][docs-img]][docs] - -[travis-img]: https://travis-ci.com/srijs/rust-crc32fast.svg?branch=master -[travis]: https://travis-ci.com/srijs/rust-crc32fast -[crates-img]: https://img.shields.io/crates/v/crc32fast.svg -[crates]: https://crates.io/crates/crc32fast -[docs-img]: https://docs.rs/crc32fast/badge.svg -[docs]: https://docs.rs/crc32fast - -_Fast, SIMD-accelerated CRC32 (IEEE) checksum computation_ - -## Usage - -```rust -extern crate crc32fast; - -use crc32fast::Hasher; - -let mut hasher = Hasher::new(); -hasher.update(b"foo bar baz"); -let checksum = hasher.finalize(); -``` - -## Performance - -This crate contains multiple CRC32 implementations: - -- A fast baseline implementation which processes up to 16 bytes per iteration -- An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions -- An optimized implementation for `aarch64` using `crc32` instructions - -Calling the `Hasher::new` constructor at runtime will perform a feature detection to select the most -optimal implementation for the current CPU feature set. - -| crate | version | variant | ns/iter | MB/s | -|-------------------------------------|---------|-----------|---------|------| -| [crc](https://crates.io/crates/crc) | 1.8.1 | n/a | 4,926 | 207 | -| crc32fast (this crate) | 1.0.0 | baseline | 683 | 1499 | -| crc32fast (this crate) | 1.0.0 | pclmulqdq | 140 | 7314 | - -## Memory Safety - -Due to the use of SIMD intrinsics for the optimized implementations, this crate contains some amount of `unsafe` code. - -In order to ensure memory safety, the relevant code has been fuzz tested using [afl.rs](https://github.com/rust-fuzz/afl.rs) with millions of iterations in both `debug` and `release` build settings. You can inspect the test setup in the `fuzz` sub-directory, which also has instructions on how to run the tests yourself. - -On top of that, every commit is tested using an address sanitizer in CI to catch any out of bounds memory accesses. - -Even though neither fuzzing not sanitization has revealed any safety bugs yet, please don't hesitate to file an issue if you run into any crashes or other unexpected behaviour. - -## Available feature flags - -### `std` (default: enabled) - -This library supports being built without the Rust `std` library, which is useful for low-level use-cases such as embedded where no operating system is available. To build the crate in a `no_std` context, disable the default `std` feature. - -Note: Because runtime CPU feature detection requires OS support, the specialized SIMD implementations will be unavailable when the `std` feature is disabled. - -### `nightly` (default: disabled) - -This feature flag enables unstable features that are only available on the `nightly` channel. Keep in mind that when enabling this feature flag, you -might experience breaking changes when updating compiler versions. - -Currently, enabling this feature flag will make the optimized `aarch64` implementation available. - -## License - -This project is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this project by you, as defined in the Apache-2.0 license, -shall be dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/benches/bench.rs b/third_party/cargo/vendor/crc32fast-1.2.0/benches/bench.rs deleted file mode 100644 index 91fbbb6..0000000 --- a/third_party/cargo/vendor/crc32fast-1.2.0/benches/bench.rs +++ /dev/null @@ -1,49 +0,0 @@ -#[macro_use] -extern crate bencher; -extern crate crc32fast; -extern crate rand; - -use bencher::Bencher; -use crc32fast::Hasher; -use rand::Rng; - -fn bench(b: &mut Bencher, size: usize, hasher_init: Hasher) { - let mut bytes = vec![0u8; size]; - rand::thread_rng().fill_bytes(&mut bytes); - - b.iter(|| { - let mut hasher = hasher_init.clone(); - hasher.update(&bytes); - bencher::black_box(hasher.finalize()) - }); - - b.bytes = size as u64; -} - -fn bench_kilobyte_baseline(b: &mut Bencher) { - bench(b, 1024, Hasher::internal_new_baseline(0)) -} - -fn bench_kilobyte_specialized(b: &mut Bencher) { - bench(b, 1024, Hasher::internal_new_specialized(0).unwrap()) -} - -fn bench_megabyte_baseline(b: &mut Bencher) { - bench(b, 1024 * 1024, Hasher::internal_new_baseline(0)) -} - -fn bench_megabyte_specialized(b: &mut Bencher) { - bench(b, 1024 * 1024, Hasher::internal_new_specialized(0).unwrap()) -} - -benchmark_group!( - bench_baseline, - bench_kilobyte_baseline, - bench_megabyte_baseline -); -benchmark_group!( - bench_specialized, - bench_kilobyte_specialized, - bench_megabyte_specialized -); -benchmark_main!(bench_baseline, bench_specialized); diff --git a/third_party/cargo/vendor/crc32fast-1.2.1/.cargo-checksum.json b/third_party/cargo/vendor/crc32fast-1.2.1/.cargo-checksum.json new file mode 100644 index 0000000..ce77fd1 --- /dev/null +++ b/third_party/cargo/vendor/crc32fast-1.2.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"15f76c4d8eb864eb816742390eb9941fd1186d67ec306252a0b78410448715d0","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"61d383b05b87d78f94d2937e2580cce47226d17823c0430fbcad09596537efcf","README.md":"6891e252b3c141f66e37ed5ed5aae15418968050a769824f2656115bd0b95137","benches/bench.rs":"b7e23cad4523e77c5c8f8e242d242cd4cd2ed855ecb9c5c42bf91116c5dc732d","build.rs":"4ccc50c3da67eb27f0b622440d2b7aee2f73fa9c71884571f3c041122231d105","src/baseline.rs":"bbe8fe49ceccbf9749052fa9c2756cf95f0fc79a063e5d3b509e3600283464ea","src/combine.rs":"7147fc4002190d36d253ea5e194e0419035b087304bcb17887efe09a8a198815","src/lib.rs":"25c55822d7fd53ff1ff0769bcffbdbcade00d45ac042a541b7189c2e94b91ee7","src/specialized/aarch64.rs":"cc8097e68f1269cee32aa856b4f7e4ba7b7472df6c2f4cecd600d292a838fe83","src/specialized/mod.rs":"bc92450e8522e9df202b346b3a209153cbb0d6587804cbfd2b947fda0f190ed6","src/specialized/pclmulqdq.rs":"6ace803b42ff70a571fd8b5f3f7c2d5a836873ce28759381c2882319b8edba70","src/table.rs":"3201c520d97c5e2cf80b8a03d72fa2e3f1270bbdf93c2fbf85498a8ea39bc64b"},"package":"81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crc32fast-1.2.1/BUILD.bazel b/third_party/cargo/vendor/crc32fast-1.2.1/BUILD.bazel new file mode 100644 index 0000000..1cf1bf2 --- /dev/null +++ b/third_party/cargo/vendor/crc32fast-1.2.1/BUILD.bazel @@ -0,0 +1,60 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "bench" with type "bench" omitted + +# Unsupported target "build-script-build" with type "custom-build" omitted + +rust_library( + name = "crc32fast", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.2.1", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/cfg-if-1.0.0:cfg_if", + ], +) diff --git a/third_party/cargo/vendor/crc32fast-1.2.1/Cargo.toml b/third_party/cargo/vendor/crc32fast-1.2.1/Cargo.toml new file mode 100644 index 0000000..d211f29 --- /dev/null +++ b/third_party/cargo/vendor/crc32fast-1.2.1/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crc32fast" +version = "1.2.1" +authors = ["Sam Rijs ", "Alex Crichton "] +description = "Fast, SIMD-accelerated CRC32 (IEEE) checksum computation" +readme = "README.md" +keywords = ["checksum", "crc", "crc32", "simd", "fast"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/srijs/rust-crc32fast" + +[[bench]] +name = "bench" +harness = false +[dependencies.cfg-if] +version = "1.0" +[dev-dependencies.bencher] +version = "0.1" + +[dev-dependencies.quickcheck] +version = "0.9" +default-features = false + +[dev-dependencies.rand] +version = "0.7" + +[features] +default = ["std"] +nightly = [] +std = [] diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/LICENSE-APACHE b/third_party/cargo/vendor/crc32fast-1.2.1/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/LICENSE-APACHE rename to third_party/cargo/vendor/crc32fast-1.2.1/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/LICENSE-MIT b/third_party/cargo/vendor/crc32fast-1.2.1/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/LICENSE-MIT rename to third_party/cargo/vendor/crc32fast-1.2.1/LICENSE-MIT diff --git a/third_party/cargo/vendor/crc32fast-1.2.1/README.md b/third_party/cargo/vendor/crc32fast-1.2.1/README.md new file mode 100644 index 0000000..0f1f78b --- /dev/null +++ b/third_party/cargo/vendor/crc32fast-1.2.1/README.md @@ -0,0 +1,81 @@ +# crc32fast [![Build Status][travis-img]][travis] [![Crates.io][crates-img]][crates] [![Documentation][docs-img]][docs] + +[travis-img]: https://travis-ci.com/srijs/rust-crc32fast.svg?branch=master +[travis]: https://travis-ci.com/srijs/rust-crc32fast +[crates-img]: https://img.shields.io/crates/v/crc32fast.svg +[crates]: https://crates.io/crates/crc32fast +[docs-img]: https://docs.rs/crc32fast/badge.svg +[docs]: https://docs.rs/crc32fast + +_Fast, SIMD-accelerated CRC32 (IEEE) checksum computation_ + +## Usage + +```rust +extern crate crc32fast; + +use crc32fast::Hasher; + +let mut hasher = Hasher::new(); +hasher.update(b"foo bar baz"); +let checksum = hasher.finalize(); +``` + +## Performance + +This crate contains multiple CRC32 implementations: + +- A fast baseline implementation which processes up to 16 bytes per iteration +- An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions +- An optimized implementation for `aarch64` using `crc32` instructions + +Calling the `Hasher::new` constructor at runtime will perform a feature detection to select the most +optimal implementation for the current CPU feature set. + +| crate | version | variant | ns/iter | MB/s | +|-------------------------------------|---------|-----------|---------|------| +| [crc](https://crates.io/crates/crc) | 1.8.1 | n/a | 4,926 | 207 | +| crc32fast (this crate) | 1.0.0 | baseline | 683 | 1499 | +| crc32fast (this crate) | 1.0.0 | pclmulqdq | 140 | 7314 | + +## Memory Safety + +Due to the use of SIMD intrinsics for the optimized implementations, this crate contains some amount of `unsafe` code. + +In order to ensure memory safety, the relevant code has been fuzz tested using [afl.rs](https://github.com/rust-fuzz/afl.rs) with millions of iterations in both `debug` and `release` build settings. You can inspect the test setup in the `fuzz` sub-directory, which also has instructions on how to run the tests yourself. + +On top of that, every commit is tested using an address sanitizer in CI to catch any out of bounds memory accesses. + +Even though neither fuzzing nor sanitization has revealed any safety bugs yet, please don't hesitate to file an issue if you run into any crashes or other unexpected behaviour. + +## Available feature flags + +### `std` (default: enabled) + +This library supports being built without the Rust `std` library, which is useful for low-level use-cases such as embedded where no operating system is available. To build the crate in a `no_std` context, disable the default `std` feature. + +Note: Because runtime CPU feature detection requires OS support, the specialized SIMD implementations will be unavailable when the `std` feature is disabled. + +### `nightly` (default: disabled) + +This feature flag enables unstable features that are only available on the `nightly` channel. Keep in mind that when enabling this feature flag, you +might experience breaking changes when updating compiler versions. + +Currently, enabling this feature flag will make the optimized `aarch64` implementation available. + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/crc32fast-1.2.1/benches/bench.rs b/third_party/cargo/vendor/crc32fast-1.2.1/benches/bench.rs new file mode 100644 index 0000000..d702df0 --- /dev/null +++ b/third_party/cargo/vendor/crc32fast-1.2.1/benches/bench.rs @@ -0,0 +1,49 @@ +#[macro_use] +extern crate bencher; +extern crate crc32fast; +extern crate rand; + +use bencher::Bencher; +use crc32fast::Hasher; +use rand::Rng; + +fn bench(b: &mut Bencher, size: usize, hasher_init: Hasher) { + let mut bytes = vec![0u8; size]; + rand::thread_rng().fill(&mut bytes[..]); + + b.iter(|| { + let mut hasher = hasher_init.clone(); + hasher.update(&bytes); + bencher::black_box(hasher.finalize()) + }); + + b.bytes = size as u64; +} + +fn bench_kilobyte_baseline(b: &mut Bencher) { + bench(b, 1024, Hasher::internal_new_baseline(0)) +} + +fn bench_kilobyte_specialized(b: &mut Bencher) { + bench(b, 1024, Hasher::internal_new_specialized(0).unwrap()) +} + +fn bench_megabyte_baseline(b: &mut Bencher) { + bench(b, 1024 * 1024, Hasher::internal_new_baseline(0)) +} + +fn bench_megabyte_specialized(b: &mut Bencher) { + bench(b, 1024 * 1024, Hasher::internal_new_specialized(0).unwrap()) +} + +benchmark_group!( + bench_baseline, + bench_kilobyte_baseline, + bench_megabyte_baseline +); +benchmark_group!( + bench_specialized, + bench_kilobyte_specialized, + bench_megabyte_specialized +); +benchmark_main!(bench_baseline, bench_specialized); diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/build.rs b/third_party/cargo/vendor/crc32fast-1.2.1/build.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/build.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/build.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/baseline.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/baseline.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/baseline.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/baseline.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/combine.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/combine.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/combine.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/combine.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/lib.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/lib.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/lib.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/lib.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/specialized/aarch64.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/specialized/aarch64.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/specialized/aarch64.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/specialized/aarch64.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/specialized/mod.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/specialized/mod.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/specialized/mod.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/specialized/mod.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/specialized/pclmulqdq.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/specialized/pclmulqdq.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/specialized/pclmulqdq.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/specialized/pclmulqdq.rs diff --git a/third_party/cargo/vendor/crc32fast-1.2.0/src/table.rs b/third_party/cargo/vendor/crc32fast-1.2.1/src/table.rs similarity index 100% rename from third_party/cargo/vendor/crc32fast-1.2.0/src/table.rs rename to third_party/cargo/vendor/crc32fast-1.2.1/src/table.rs diff --git a/third_party/cargo/vendor/crossbeam-0.7.3/BUILD.bazel b/third_party/cargo/vendor/crossbeam-0.7.3/BUILD.bazel index cbd97f5..7c3f2d0 100644 --- a/third_party/cargo/vendor/crossbeam-0.7.3/BUILD.bazel +++ b/third_party/cargo/vendor/crossbeam-0.7.3/BUILD.bazel @@ -55,10 +55,10 @@ rust_library( # buildifier: leave-alone deps = [ "//third_party/cargo/vendor/cfg-if-0.1.10:cfg_if", - "//third_party/cargo/vendor/crossbeam-channel-0.4.2:crossbeam_channel", + "//third_party/cargo/vendor/crossbeam-channel-0.4.4:crossbeam_channel", "//third_party/cargo/vendor/crossbeam-deque-0.7.3:crossbeam_deque", "//third_party/cargo/vendor/crossbeam-epoch-0.8.2:crossbeam_epoch", - "//third_party/cargo/vendor/crossbeam-queue-0.2.2:crossbeam_queue", + "//third_party/cargo/vendor/crossbeam-queue-0.2.3:crossbeam_queue", "//third_party/cargo/vendor/crossbeam-utils-0.7.2:crossbeam_utils", ], ) diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-channel-0.4.2/.cargo-checksum.json deleted file mode 100644 index e3095e7..0000000 --- a/third_party/cargo/vendor/crossbeam-channel-0.4.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"40140368f7acf7657e37bedea150e10b9ba38b50b98b1b234c076ffc470af1ca","Cargo.lock":"476677c500d3cff5eedb562013fa5352560a66bf0fe30be758f4e4055cbe5986","Cargo.toml":"a0642274b237f6996a61472bad73512ec5f6d1559cf8891714f7806d344bb64b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"924a49392dc8304def57586be4ebd69aaf51e16fd245b55b4b69ad2cce6b715a","README.md":"7967172d90f7ebc20531d76c5a2bad7be8d81670fbc64abc33be4315d1430757","benches/crossbeam.rs":"baef02dffd58ee4d84d33a4e999254e81fcf45241623cfa6c4b1ef73dbd7479d","examples/fibonacci.rs":"8755bcb9cf05e391d8679fbb51db40ed9692703c3b66341cd1c1e4cca2068874","examples/matching.rs":"a1bdd7d211cf8612d649de3de3e24f56e911bc8d5e95b86b06f412314f9edd6c","examples/stopwatch.rs":"4e90ce134475859a421da0a095baea52a575b03e41fb8fb50cf47446f422ee6e","src/channel.rs":"4483ddf38c4b9b308b81dd156653ccb590524aae1e5ff8efcab6b8f44a8d3dfc","src/context.rs":"48eb848538482aeadd5bafb8fd24695dcf5635243d6f9d3b059a22538ce67014","src/counter.rs":"8b6d4d69db59bc992ddc7ed33f709788c3fab482521bb1adf985f77499506c09","src/err.rs":"80c47848fbfeeabaa83ea49c0928274cd4ae0ced7ebf214a075322fe301f3fa6","src/flavors/after.rs":"4f761618efe21036145e44f01506bdfbc2524879368ac138600e0feed921a6a7","src/flavors/array.rs":"606e27d3376c3cee128656b3690bd429964a22e3078886b6b7bf10cfa072fabb","src/flavors/list.rs":"0e2bf126b07ba8c2ef5db881043a3987b5f91013d47ae2da147a1c61a033c320","src/flavors/mod.rs":"a5af9b6105207e293c0d64928b4486fb1da9bfe0318354c66c8b5069e41ec31f","src/flavors/never.rs":"86e21b4d8b154e5d795cf72c7203a1d16a846c4d670095c8b592c12569f35a98","src/flavors/tick.rs":"d80858e0d5d1d7ec3886fb607e49bbc9577d64dc7c7304c5d3e6c8629a065476","src/flavors/zero.rs":"a24c2fb547586ab4bf2a09efb8af5264274f7b373749cd259a7dd3c843c8aac5","src/lib.rs":"1f0e6c4fb470dfe2fbdda90b7ac17f72c32fd62d41bccb4db9a756a88481fb44","src/select.rs":"f917459c033f8edbb45f377d6a4af24ffb583583d039182e72252d4af64a8807","src/select_macro.rs":"b1a3d2b9d4c64b48f6b176d2ff8b44c3d754f157ddbe830e8a1e86e4c100e0e9","src/utils.rs":"8b1184222df9047355e6044ad7e3fefd6065a5dda98b968cae45cca5f4b2fb5d","src/waker.rs":"345b551d467389a3a18dc22b351674dfbf288945b984450f607e644faa8a9731","tests/after.rs":"effb341c02f03a45ce09ab7862bc5b191191e0175997c494f988e6daca1ef8af","tests/array.rs":"35cd46fc7310f4206e3bbd81f900c18053a3a22943e221fbb81f9b89505fee46","tests/golang.rs":"9cb210ef2668428f7efb542ff4a8ab4e61f77dd4ff7e39720d63ad0797ff4ec1","tests/iter.rs":"b6df3f21273bb21dfecda47ffc0c296541214cde6bed876a31db5f2410839e83","tests/list.rs":"eb6cfc9a0f02c77df6d6d608fbbe1f82e09901e167b4b86993c49f9d6052a8ee","tests/mpsc.rs":"965e18abbfcdebec09380f8ec9bb62e5556ad2aa0176ed088ce091994c1d2500","tests/never.rs":"cd455a4c78403d9a96fe0f3a4e968164cca533cc85c96aaa4558987f9b088fcc","tests/ready.rs":"b91cebde45a6c46bd2cf16b1fc58b2ec258dcc960cb9f8eb5b4c39b1a144cadc","tests/same_channel.rs":"bd93f72e982f9881235848a4a2da67276feca810ed1e4d22e0e2bda8675cae4a","tests/select.rs":"57558f93834dc1ae1a56fe8d1211536e16015a74c8c7458c653852472c21ddcd","tests/select_macro.rs":"1cd5250d46d6d2e8c0a87ee9b1c0a5d80aac193c3eb0a86877249684e7aabd39","tests/thread_locals.rs":"845f8c8f1a37a14e4235fc9fc20d8b7288fd9fda307c075c0e61e6ab79b33921","tests/tick.rs":"dd4257f1f8de01477d542e20a816eede3b4e2e4dc6fcdf07d554220f0ef8a86f","tests/zero.rs":"088804df377904eca4a985d8f1703f98550e51304d6849bfce143fcd0b69c349"},"package":"cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/BUILD.bazel b/third_party/cargo/vendor/crossbeam-channel-0.4.2/BUILD.bazel deleted file mode 100644 index b3a74cf..0000000 --- a/third_party/cargo/vendor/crossbeam-channel-0.4.2/BUILD.bazel +++ /dev/null @@ -1,91 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR (Apache-2.0 AND BSD-2-Clause)" -]) - -# Generated Targets - -# Unsupported target "crossbeam" with type "bench" omitted - -# Unsupported target "fibonacci" with type "example" omitted - -# Unsupported target "matching" with type "example" omitted - -# Unsupported target "stopwatch" with type "example" omitted - -rust_library( - name = "crossbeam_channel", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.4.2", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/crossbeam-utils-0.7.2:crossbeam_utils", - "//third_party/cargo/vendor/maybe-uninit-2.0.0:maybe_uninit", - ], -) - -# Unsupported target "after" with type "test" omitted - -# Unsupported target "array" with type "test" omitted - -# Unsupported target "golang" with type "test" omitted - -# Unsupported target "iter" with type "test" omitted - -# Unsupported target "list" with type "test" omitted - -# Unsupported target "mpsc" with type "test" omitted - -# Unsupported target "never" with type "test" omitted - -# Unsupported target "ready" with type "test" omitted - -# Unsupported target "same_channel" with type "test" omitted - -# Unsupported target "select" with type "test" omitted - -# Unsupported target "select_macro" with type "test" omitted - -# Unsupported target "thread_locals" with type "test" omitted - -# Unsupported target "tick" with type "test" omitted - -# Unsupported target "zero" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-channel-0.4.2/CHANGELOG.md deleted file mode 100644 index c1fcf3f..0000000 --- a/third_party/cargo/vendor/crossbeam-channel-0.4.2/CHANGELOG.md +++ /dev/null @@ -1,158 +0,0 @@ -# Version 0.4.2 - -- Fix bug in release (yanking 0.4.1) - -# Version 0.4.1 - -- Avoid time drift in `channel::tick`. (#456) -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) - -# Version 0.4.0 - -- Bump the minimum required version to 1.28. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.3.9 - -- Fix a bug in reference counting. -- Optimize `recv_timeout()`. -- Add `Select::remove()`. -- Various small improvements, code cleanup, more tests. - -# Version 0.3.8 - -- Bump the minimum required version of `crossbeam-utils`. - -# Version 0.3.7 - -- Remove `parking_lot` and `rand` dependencies. -- Expand documentation. -- Implement `Default` for `Select`. -- Make `size_of::>()` smaller. -- Several minor optimizations. -- Add more tests. - -# Version 0.3.6 - -- Fix a bug in initialization of unbounded channels. - -# Version 0.3.5 - -- New implementation for unbounded channels. -- A number of small performance improvements. -- Remove `crossbeam-epoch` dependency. - -# Version 0.3.4 - -- Bump `crossbeam-epoch` to `0.7`. -- Improve documentation. - -# Version 0.3.3 - -- Relax the lifetime in `SelectedOperation<'_>`. -- Add `Select::try_ready()`, `Select::ready()`, and `Select::ready_timeout()`. -- Update licensing notices. -- Improve documentation. -- Add methods `is_disconnected()`, `is_timeout()`, `is_empty()`, and `is_full()` on error types. - -# Version 0.3.2 - -- More elaborate licensing notices. - -# Version 0.3.1 - -- Update `crossbeam-utils` to `0.6`. - -# Version 0.3.0 - -- Add a special `never` channel type. -- Dropping all receivers now closes the channel. -- The interface of sending and receiving methods is now very similar to those in v0.1. -- The syntax for `send` in `select!` is now `send(sender, msg) -> res => body`. -- The syntax for `recv` in `select!` is now `recv(receiver) -> res => body`. -- New, more efficient interface for `Select` without callbacks. -- Timeouts can be specified in `select!`. - -# Version 0.2.6 - -- `Select` struct that can add cases dynamically. -- More documentation (in particular, the FAQ section). -- Optimize contended sends/receives in unbounded channels. - -# Version 0.2.5 - -- Use `LocalKey::try_with` instead of `LocalKey::with`. -- Remove helper macros `__crossbeam_channel*`. - -# Version 0.2.4 - -- Make `select!` linearizable with other channel operations. -- Update `crossbeam-utils` to `0.5.0`. -- Update `parking_lot` to `0.6.3`. -- Remove Mac OS X tests. - -# Version 0.2.3 - -- Add Mac OS X tests. -- Lower some memory orderings. -- Eliminate calls to `mem::unitialized`, which caused bugs with ZST. - -# Version 0.2.2 - -- Add more tests. -- Update `crossbeam-epoch` to 0.5.0 -- Initialize the RNG seed to a random value. -- Replace `libc::abort` with `std::process::abort`. -- Ignore clippy warnings in `select!`. -- Better interaction of `select!` with the NLL borrow checker. - -# Version 0.2.1 - -- Fix compilation errors when using `select!` with `#[deny(unsafe_code)]`. - -# Version 0.2.0 - -- Implement `IntoIterator` for `Receiver`. -- Add a new `select!` macro. -- Add special channels `after` and `tick`. -- Dropping receivers doesn't close the channel anymore. -- Change the signature of `recv`, `send`, and `try_recv`. -- Remove `Sender::is_closed` and `Receiver::is_closed`. -- Remove `Sender::close` and `Receiver::close`. -- Remove `Sender::send_timeout` and `Receiver::recv_timeout`. -- Remove `Sender::try_send`. -- Remove `Select` and `select_loop!`. -- Remove all error types. -- Remove `Iter`, `TryIter`, and `IntoIter`. -- Remove the `nightly` feature. -- Remove ordering operators for `Sender` and `Receiver`. - -# Version 0.1.3 - -- Add `Sender::disconnect` and `Receiver::disconnect`. -- Implement comparison operators for `Sender` and `Receiver`. -- Allow arbitrary patterns in place of `msg` in `recv(r, msg)`. -- Add a few conversion impls between error types. -- Add benchmarks for `atomicring` and `mpmc`. -- Add benchmarks for different message sizes. -- Documentation improvements. -- Update `crossbeam-epoch` to 0.4.0 -- Update `crossbeam-utils` to 0.3.0 -- Update `parking_lot` to 0.5 -- Update `rand` to 0.4 - -# Version 0.1.2 - -- Allow conditional cases in `select_loop!` macro. -- Fix typos in documentation. -- Fix deadlock in selection when all channels are disconnected and a timeout is specified. - -# Version 0.1.1 - -- Implement `Debug` for `Sender`, `Receiver`, `Iter`, `TryIter`, `IntoIter`, and `Select`. -- Implement `Default` for `Select`. - -# Version 0.1.0 - -- First implementation of the channels. -- Add `select_loop!` macro by @TimNN. diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/Cargo.lock b/third_party/cargo/vendor/crossbeam-channel-0.4.2/Cargo.lock deleted file mode 100644 index 5559700..0000000 --- a/third_party/cargo/vendor/crossbeam-channel-0.4.2/Cargo.lock +++ /dev/null @@ -1,264 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "arc-swap" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-channel" -version = "0.4.2" -dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hermit-abi" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.67" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "signal-hook" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "signal-hook-registry" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "10b9f3a1686a29f53cfd91ee5e3db3c12313ec02d33765f02c1a9645a1811e2c" -"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/Cargo.toml b/third_party/cargo/vendor/crossbeam-channel-0.4.2/Cargo.toml deleted file mode 100644 index 0b700b1..0000000 --- a/third_party/cargo/vendor/crossbeam-channel-0.4.2/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "crossbeam-channel" -version = "0.4.2" -authors = ["The Crossbeam Project Developers"] -description = "Multi-producer multi-consumer channels for message passing" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" -documentation = "https://docs.rs/crossbeam-channel" -readme = "README.md" -keywords = ["channel", "mpmc", "select", "golang", "message"] -categories = ["algorithms", "concurrency", "data-structures"] -license = "MIT/Apache-2.0 AND BSD-2-Clause" -repository = "https://github.com/crossbeam-rs/crossbeam" -[dependencies.crossbeam-utils] -version = "0.7" - -[dependencies.maybe-uninit] -version = "2.0.0" -[dev-dependencies.num_cpus] -version = "1.10.0" - -[dev-dependencies.rand] -version = "0.6" - -[dev-dependencies.signal-hook] -version = "0.1.5" diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.4/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-channel-0.4.4/.cargo-checksum.json new file mode 100644 index 0000000..61a680a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.4.4/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d55a5f1a75b60fbbd53a5b1432f19b8fa7e2bb822e1cc93ec956e542e7e8b3cd","Cargo.lock":"dcb3de08ddba81cf97f49253b63b8eb4f386338c0db8d4b77ae943fc138bfe69","Cargo.toml":"c20147fdaf2d6e99fe30c9f639fc0339f6af18994c2756cba1c869cd8e198bc0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"924a49392dc8304def57586be4ebd69aaf51e16fd245b55b4b69ad2cce6b715a","README.md":"7967172d90f7ebc20531d76c5a2bad7be8d81670fbc64abc33be4315d1430757","benches/crossbeam.rs":"baef02dffd58ee4d84d33a4e999254e81fcf45241623cfa6c4b1ef73dbd7479d","examples/fibonacci.rs":"8755bcb9cf05e391d8679fbb51db40ed9692703c3b66341cd1c1e4cca2068874","examples/matching.rs":"a1bdd7d211cf8612d649de3de3e24f56e911bc8d5e95b86b06f412314f9edd6c","examples/stopwatch.rs":"4e90ce134475859a421da0a095baea52a575b03e41fb8fb50cf47446f422ee6e","src/channel.rs":"4483ddf38c4b9b308b81dd156653ccb590524aae1e5ff8efcab6b8f44a8d3dfc","src/context.rs":"48eb848538482aeadd5bafb8fd24695dcf5635243d6f9d3b059a22538ce67014","src/counter.rs":"8b6d4d69db59bc992ddc7ed33f709788c3fab482521bb1adf985f77499506c09","src/err.rs":"80c47848fbfeeabaa83ea49c0928274cd4ae0ced7ebf214a075322fe301f3fa6","src/flavors/after.rs":"4f761618efe21036145e44f01506bdfbc2524879368ac138600e0feed921a6a7","src/flavors/array.rs":"606e27d3376c3cee128656b3690bd429964a22e3078886b6b7bf10cfa072fabb","src/flavors/list.rs":"0e2bf126b07ba8c2ef5db881043a3987b5f91013d47ae2da147a1c61a033c320","src/flavors/mod.rs":"a5af9b6105207e293c0d64928b4486fb1da9bfe0318354c66c8b5069e41ec31f","src/flavors/never.rs":"86e21b4d8b154e5d795cf72c7203a1d16a846c4d670095c8b592c12569f35a98","src/flavors/tick.rs":"d80858e0d5d1d7ec3886fb607e49bbc9577d64dc7c7304c5d3e6c8629a065476","src/flavors/zero.rs":"a24c2fb547586ab4bf2a09efb8af5264274f7b373749cd259a7dd3c843c8aac5","src/lib.rs":"1f0e6c4fb470dfe2fbdda90b7ac17f72c32fd62d41bccb4db9a756a88481fb44","src/select.rs":"f917459c033f8edbb45f377d6a4af24ffb583583d039182e72252d4af64a8807","src/select_macro.rs":"b1a3d2b9d4c64b48f6b176d2ff8b44c3d754f157ddbe830e8a1e86e4c100e0e9","src/utils.rs":"8b1184222df9047355e6044ad7e3fefd6065a5dda98b968cae45cca5f4b2fb5d","src/waker.rs":"345b551d467389a3a18dc22b351674dfbf288945b984450f607e644faa8a9731","tests/after.rs":"effb341c02f03a45ce09ab7862bc5b191191e0175997c494f988e6daca1ef8af","tests/array.rs":"35cd46fc7310f4206e3bbd81f900c18053a3a22943e221fbb81f9b89505fee46","tests/golang.rs":"9cb210ef2668428f7efb542ff4a8ab4e61f77dd4ff7e39720d63ad0797ff4ec1","tests/iter.rs":"b6df3f21273bb21dfecda47ffc0c296541214cde6bed876a31db5f2410839e83","tests/list.rs":"eb6cfc9a0f02c77df6d6d608fbbe1f82e09901e167b4b86993c49f9d6052a8ee","tests/mpsc.rs":"965e18abbfcdebec09380f8ec9bb62e5556ad2aa0176ed088ce091994c1d2500","tests/never.rs":"cd455a4c78403d9a96fe0f3a4e968164cca533cc85c96aaa4558987f9b088fcc","tests/ready.rs":"b91cebde45a6c46bd2cf16b1fc58b2ec258dcc960cb9f8eb5b4c39b1a144cadc","tests/same_channel.rs":"bd93f72e982f9881235848a4a2da67276feca810ed1e4d22e0e2bda8675cae4a","tests/select.rs":"57558f93834dc1ae1a56fe8d1211536e16015a74c8c7458c653852472c21ddcd","tests/select_macro.rs":"1cd5250d46d6d2e8c0a87ee9b1c0a5d80aac193c3eb0a86877249684e7aabd39","tests/thread_locals.rs":"845f8c8f1a37a14e4235fc9fc20d8b7288fd9fda307c075c0e61e6ab79b33921","tests/tick.rs":"dd4257f1f8de01477d542e20a816eede3b4e2e4dc6fcdf07d554220f0ef8a86f","tests/zero.rs":"088804df377904eca4a985d8f1703f98550e51304d6849bfce143fcd0b69c349"},"package":"b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.4/BUILD.bazel b/third_party/cargo/vendor/crossbeam-channel-0.4.4/BUILD.bazel new file mode 100644 index 0000000..ff01f96 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.4.4/BUILD.bazel @@ -0,0 +1,91 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "crossbeam" with type "bench" omitted + +# Unsupported target "fibonacci" with type "example" omitted + +# Unsupported target "matching" with type "example" omitted + +# Unsupported target "stopwatch" with type "example" omitted + +rust_library( + name = "crossbeam_channel", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.4.4", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/crossbeam-utils-0.7.2:crossbeam_utils", + "//third_party/cargo/vendor/maybe-uninit-2.0.0:maybe_uninit", + ], +) + +# Unsupported target "after" with type "test" omitted + +# Unsupported target "array" with type "test" omitted + +# Unsupported target "golang" with type "test" omitted + +# Unsupported target "iter" with type "test" omitted + +# Unsupported target "list" with type "test" omitted + +# Unsupported target "mpsc" with type "test" omitted + +# Unsupported target "never" with type "test" omitted + +# Unsupported target "ready" with type "test" omitted + +# Unsupported target "same_channel" with type "test" omitted + +# Unsupported target "select" with type "test" omitted + +# Unsupported target "select_macro" with type "test" omitted + +# Unsupported target "thread_locals" with type "test" omitted + +# Unsupported target "tick" with type "test" omitted + +# Unsupported target "zero" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.4/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-channel-0.4.4/CHANGELOG.md new file mode 100644 index 0000000..8c1c7fc --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.4.4/CHANGELOG.md @@ -0,0 +1,167 @@ +# Version 0.4.4 + +- Fix bug in release (yanking 0.4.3) +- Fix UB and breaking change introduced in 0.4.3 + +# Version 0.4.3 + +- Change license to "MIT OR Apache-2.0". + +# Version 0.4.2 + +- Fix bug in release (yanking 0.4.1) + +# Version 0.4.1 + +- Avoid time drift in `channel::tick`. (#456) +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) + +# Version 0.4.0 + +- Bump the minimum required version to 1.28. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.3.9 + +- Fix a bug in reference counting. +- Optimize `recv_timeout()`. +- Add `Select::remove()`. +- Various small improvements, code cleanup, more tests. + +# Version 0.3.8 + +- Bump the minimum required version of `crossbeam-utils`. + +# Version 0.3.7 + +- Remove `parking_lot` and `rand` dependencies. +- Expand documentation. +- Implement `Default` for `Select`. +- Make `size_of::>()` smaller. +- Several minor optimizations. +- Add more tests. + +# Version 0.3.6 + +- Fix a bug in initialization of unbounded channels. + +# Version 0.3.5 + +- New implementation for unbounded channels. +- A number of small performance improvements. +- Remove `crossbeam-epoch` dependency. + +# Version 0.3.4 + +- Bump `crossbeam-epoch` to `0.7`. +- Improve documentation. + +# Version 0.3.3 + +- Relax the lifetime in `SelectedOperation<'_>`. +- Add `Select::try_ready()`, `Select::ready()`, and `Select::ready_timeout()`. +- Update licensing notices. +- Improve documentation. +- Add methods `is_disconnected()`, `is_timeout()`, `is_empty()`, and `is_full()` on error types. + +# Version 0.3.2 + +- More elaborate licensing notices. + +# Version 0.3.1 + +- Update `crossbeam-utils` to `0.6`. + +# Version 0.3.0 + +- Add a special `never` channel type. +- Dropping all receivers now closes the channel. +- The interface of sending and receiving methods is now very similar to those in v0.1. +- The syntax for `send` in `select!` is now `send(sender, msg) -> res => body`. +- The syntax for `recv` in `select!` is now `recv(receiver) -> res => body`. +- New, more efficient interface for `Select` without callbacks. +- Timeouts can be specified in `select!`. + +# Version 0.2.6 + +- `Select` struct that can add cases dynamically. +- More documentation (in particular, the FAQ section). +- Optimize contended sends/receives in unbounded channels. + +# Version 0.2.5 + +- Use `LocalKey::try_with` instead of `LocalKey::with`. +- Remove helper macros `__crossbeam_channel*`. + +# Version 0.2.4 + +- Make `select!` linearizable with other channel operations. +- Update `crossbeam-utils` to `0.5.0`. +- Update `parking_lot` to `0.6.3`. +- Remove Mac OS X tests. + +# Version 0.2.3 + +- Add Mac OS X tests. +- Lower some memory orderings. +- Eliminate calls to `mem::unitialized`, which caused bugs with ZST. + +# Version 0.2.2 + +- Add more tests. +- Update `crossbeam-epoch` to 0.5.0 +- Initialize the RNG seed to a random value. +- Replace `libc::abort` with `std::process::abort`. +- Ignore clippy warnings in `select!`. +- Better interaction of `select!` with the NLL borrow checker. + +# Version 0.2.1 + +- Fix compilation errors when using `select!` with `#[deny(unsafe_code)]`. + +# Version 0.2.0 + +- Implement `IntoIterator` for `Receiver`. +- Add a new `select!` macro. +- Add special channels `after` and `tick`. +- Dropping receivers doesn't close the channel anymore. +- Change the signature of `recv`, `send`, and `try_recv`. +- Remove `Sender::is_closed` and `Receiver::is_closed`. +- Remove `Sender::close` and `Receiver::close`. +- Remove `Sender::send_timeout` and `Receiver::recv_timeout`. +- Remove `Sender::try_send`. +- Remove `Select` and `select_loop!`. +- Remove all error types. +- Remove `Iter`, `TryIter`, and `IntoIter`. +- Remove the `nightly` feature. +- Remove ordering operators for `Sender` and `Receiver`. + +# Version 0.1.3 + +- Add `Sender::disconnect` and `Receiver::disconnect`. +- Implement comparison operators for `Sender` and `Receiver`. +- Allow arbitrary patterns in place of `msg` in `recv(r, msg)`. +- Add a few conversion impls between error types. +- Add benchmarks for `atomicring` and `mpmc`. +- Add benchmarks for different message sizes. +- Documentation improvements. +- Update `crossbeam-epoch` to 0.4.0 +- Update `crossbeam-utils` to 0.3.0 +- Update `parking_lot` to 0.5 +- Update `rand` to 0.4 + +# Version 0.1.2 + +- Allow conditional cases in `select_loop!` macro. +- Fix typos in documentation. +- Fix deadlock in selection when all channels are disconnected and a timeout is specified. + +# Version 0.1.1 + +- Implement `Debug` for `Sender`, `Receiver`, `Iter`, `TryIter`, `IntoIter`, and `Select`. +- Implement `Default` for `Select`. + +# Version 0.1.0 + +- First implementation of the channels. +- Add `select_loop!` macro by @TimNN. diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.4/Cargo.lock b/third_party/cargo/vendor/crossbeam-channel-0.4.4/Cargo.lock new file mode 100644 index 0000000..fe038cc --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.4.4/Cargo.lock @@ -0,0 +1,262 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arc-swap" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", + "num_cpus", + "rand", + "signal-hook", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "signal-hook" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +dependencies = [ + "arc-swap", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.4/Cargo.toml b/third_party/cargo/vendor/crossbeam-channel-0.4.4/Cargo.toml new file mode 100644 index 0000000..86f264b --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.4.4/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crossbeam-channel" +version = "0.4.4" +authors = ["The Crossbeam Project Developers"] +description = "Multi-producer multi-consumer channels for message passing" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" +documentation = "https://docs.rs/crossbeam-channel" +readme = "README.md" +keywords = ["channel", "mpmc", "select", "golang", "message"] +categories = ["algorithms", "concurrency", "data-structures"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dependencies.crossbeam-utils] +version = "0.7" + +[dependencies.maybe-uninit] +version = "2.0.0" +[dev-dependencies.num_cpus] +version = "1.10.0" + +[dev-dependencies.rand] +version = "0.6" + +[dev-dependencies.signal-hook] +version = "0.1.5" diff --git a/third_party/cargo/vendor/core-graphics-0.19.0/LICENSE-APACHE b/third_party/cargo/vendor/crossbeam-channel-0.4.4/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/core-graphics-0.19.0/LICENSE-APACHE rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/LICENSE-MIT b/third_party/cargo/vendor/crossbeam-channel-0.4.4/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/LICENSE-MIT rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/LICENSE-MIT diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/LICENSE-THIRD-PARTY b/third_party/cargo/vendor/crossbeam-channel-0.4.4/LICENSE-THIRD-PARTY similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/LICENSE-THIRD-PARTY rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/LICENSE-THIRD-PARTY diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/README.md b/third_party/cargo/vendor/crossbeam-channel-0.4.4/README.md similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/README.md rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/README.md diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/benches/crossbeam.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/benches/crossbeam.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/benches/crossbeam.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/benches/crossbeam.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/examples/fibonacci.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/examples/fibonacci.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/examples/fibonacci.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/examples/fibonacci.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/examples/matching.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/examples/matching.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/examples/matching.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/examples/matching.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/examples/stopwatch.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/examples/stopwatch.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/examples/stopwatch.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/examples/stopwatch.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/channel.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/channel.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/channel.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/channel.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/context.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/context.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/context.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/context.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/counter.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/counter.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/counter.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/counter.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/err.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/err.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/err.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/err.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/after.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/after.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/after.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/after.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/array.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/array.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/array.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/array.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/list.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/list.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/list.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/list.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/mod.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/mod.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/mod.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/mod.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/never.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/never.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/never.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/never.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/tick.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/tick.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/tick.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/tick.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/zero.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/zero.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/flavors/zero.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/flavors/zero.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/lib.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/lib.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/lib.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/lib.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/select.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/select.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/select.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/select.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/select_macro.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/select_macro.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/select_macro.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/select_macro.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/utils.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/utils.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/utils.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/utils.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/src/waker.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/src/waker.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/src/waker.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/src/waker.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/after.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/after.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/after.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/after.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/array.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/array.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/array.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/array.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/golang.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/golang.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/golang.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/golang.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/iter.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/iter.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/iter.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/iter.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/list.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/list.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/list.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/list.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/mpsc.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/mpsc.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/mpsc.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/mpsc.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/never.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/never.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/never.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/never.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/ready.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/ready.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/ready.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/ready.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/same_channel.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/same_channel.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/same_channel.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/same_channel.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/select.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/select.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/select.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/select.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/select_macro.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/select_macro.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/select_macro.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/select_macro.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/thread_locals.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/thread_locals.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/thread_locals.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/thread_locals.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/tick.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/tick.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/tick.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/tick.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/zero.rs b/third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/zero.rs similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/tests/zero.rs rename to third_party/cargo/vendor/crossbeam-channel-0.4.4/tests/zero.rs diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-channel-0.5.0/.cargo-checksum.json new file mode 100644 index 0000000..e232bc9 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"0d433ba4c2a327604b582aa0cdbe7b841ee9dcca526f6cb368a07c389c485096","Cargo.lock":"97e544df9b9e169d315994dc220e7a274ac039a3a4f372f7cab333a2e93d9b96","Cargo.toml":"a493466e1330e58126818f0e46b82350ad9e6a7811ca6817159fcdd89c8c871a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"924a49392dc8304def57586be4ebd69aaf51e16fd245b55b4b69ad2cce6b715a","README.md":"d2c041f6fa5da30a6f87377421a8de4010c0c002dbff777e18ad2f8b36a65378","benches/crossbeam.rs":"f5720508d3458f2451271b9887f7557823304bd38288c928b0d6aa1f459865e5","examples/fibonacci.rs":"6a26ecd74c7493d2c93f4280c0804afc19adc612b77b3d9fea433119ff472a44","examples/matching.rs":"63c250e164607a7a9f643d46f107bb5da846d49e89cf9069909562d20e530f71","examples/stopwatch.rs":"87e4613e24083e877d97aaefdc6c78ee0308c3a2994974b2cbc7df042a82d488","src/channel.rs":"de23e68e7fa16a1e3278bd69f22fd499724e21533b2b601a71dada9cdda97181","src/context.rs":"ad24cabfc50dd5e6ae84aa46a0246da12da1f1a6fa19043244ad25136075c6ca","src/counter.rs":"8b6d4d69db59bc992ddc7ed33f709788c3fab482521bb1adf985f77499506c09","src/err.rs":"fdbde7279a1e74973e5c7d3e835a97836229a357fe465c0ba1a37f2a012d1bef","src/flavors/array.rs":"59d43e7292f5e3f7f1bb7799fdf99d97aae763ac93d2c1c2e0e807cbbae1657b","src/flavors/at.rs":"e6a169d91ee1057080b0ef55f3e38471212b4ef225e2cdc2fd25b2262371f921","src/flavors/list.rs":"fa6667a33e30fad94a8432b78dd70d143e0809ebf80fa881bb6221aca55b4229","src/flavors/mod.rs":"6188db53712b10add58364e3031101833d9fb0e384f3a2894c38c8b11abe4cdf","src/flavors/never.rs":"59ac4a46b5e32780b2b2f338064544a8b4ec1bc8b78a8a9cd0a683bcd01d5d36","src/flavors/tick.rs":"667fcaacb07d7556350a7e59b5906956224c57b1f43b7b0018a5e2dad0d91ff8","src/flavors/zero.rs":"97c13c89bce0ffd4f761a5ecd73e3221bdd320817061ef7bc7d76010da021b77","src/lib.rs":"5873568968cfd92c6970ef9c3b2643a9d68c61f2fe4c724e52243f3b555de758","src/select.rs":"da9446e51bdcc51e878e71d7a97f0b718639ea065d7ddf4fa7b561efebc84a0e","src/select_macro.rs":"96bc9acb9a22588a4e733b0ab0761ad2be9a6b3e03744e8fc9c6de9ae433b696","src/utils.rs":"4ec0d30835f42dffc7614a18c8f005abb40dd33f2b127809b297959c6aa43004","src/waker.rs":"27eb84dcd0eb58f7d0d79d412bb293becc2740f6166d2fc64acb0ad94cfb523e","tests/after.rs":"324c7d773f72bef62d150171f74ba7b7ac1b06f6030b3d4d2b1a35d211956b21","tests/array.rs":"62290dfd66740a1d1017daea8048df09a11ee8ff8eb614a3a0aa5f4d456a7c39","tests/golang.rs":"751743529b0354d152916e0854a0387ca0b3a898a1771c46e1e7fa2b1660edf9","tests/iter.rs":"7563dc7fdf4c63e31dd74ee3fedecdd3aed490f7ef599b98f6f75f929cf79edb","tests/list.rs":"6a9645c00aed88c1ad07d2e416b4f137ccef2e50f389c71589c6ac7d57373e5a","tests/mpsc.rs":"0c4c6b056f5cec77ca19eca45f99b083632700a4b67133e88071a1d22a61d6fe","tests/never.rs":"665441a9fb004f7cd44047619637ebe6766cf2faf58e68e6481397bbfc682e11","tests/ready.rs":"3848ee8bb16cc83269a462d830659ff29f91834eaab0749bca7be02f43d7db51","tests/same_channel.rs":"2bab761443671e841e1b2476bd8082d75533a2f6be7946f5dbcee67cdc82dccb","tests/select.rs":"58aa5421475bd98b3adc02e4241fc77669ca910cf9cac7a8b0a212b2e92cb7c7","tests/select_macro.rs":"00dd7963f79b96abf30851fdab29e86c8424b502a8a7d34abf4bc1714f493ecf","tests/thread_locals.rs":"3611db5502e6af0a8d15187d09fd195381819795544208b946e9f99b04579a81","tests/tick.rs":"06f205ace5fc44daaf1b6900a2e05bb5bda1c6071c1a07524f45769d8855968b","tests/zero.rs":"368eac99c6d9fb679f8dfbe93cdb96b01d77d1b6f840aa4e156b06f1786bb882"},"package":"dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/BUILD.bazel b/third_party/cargo/vendor/crossbeam-channel-0.5.0/BUILD.bazel new file mode 100644 index 0000000..9be47fb --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/BUILD.bazel @@ -0,0 +1,94 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "crossbeam" with type "bench" omitted + +# Unsupported target "fibonacci" with type "example" omitted + +# Unsupported target "matching" with type "example" omitted + +# Unsupported target "stopwatch" with type "example" omitted + +rust_library( + name = "crossbeam_channel", + srcs = glob(["**/*.rs"]), + crate_features = [ + "crossbeam-utils", + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.5.0", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/cfg-if-1.0.0:cfg_if", + "//third_party/cargo/vendor/crossbeam-utils-0.8.1:crossbeam_utils", + ], +) + +# Unsupported target "after" with type "test" omitted + +# Unsupported target "array" with type "test" omitted + +# Unsupported target "golang" with type "test" omitted + +# Unsupported target "iter" with type "test" omitted + +# Unsupported target "list" with type "test" omitted + +# Unsupported target "mpsc" with type "test" omitted + +# Unsupported target "never" with type "test" omitted + +# Unsupported target "ready" with type "test" omitted + +# Unsupported target "same_channel" with type "test" omitted + +# Unsupported target "select" with type "test" omitted + +# Unsupported target "select_macro" with type "test" omitted + +# Unsupported target "thread_locals" with type "test" omitted + +# Unsupported target "tick" with type "test" omitted + +# Unsupported target "zero" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-channel-0.5.0/CHANGELOG.md new file mode 100644 index 0000000..0a53e8a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/CHANGELOG.md @@ -0,0 +1,176 @@ +# Version 0.5.0 + +- Bump the minimum supported Rust version to 1.36. +- Add `at()` function. +- Add `Sender::send_deadline()` and `Receiver::recv_deadline()` methods. +- Add `Select::select_deadline()` and `Select::ready_deadline()` methods. +- Add `std` (enabled by default) feature for forward compatibility. +- Allow `select!` macro compile with `forbid(unsafe_code)`. + +# Version 0.4.4 + +- Fix bug in release (yanking 0.4.3) +- Fix UB and breaking change introduced in 0.4.3 + +# Version 0.4.3 + +- Change license to "MIT OR Apache-2.0". + +# Version 0.4.2 + +- Fix bug in release (yanking 0.4.1) + +# Version 0.4.1 + +- Avoid time drift in `channel::tick`. (#456) +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) + +# Version 0.4.0 + +- Bump the minimum required version to 1.28. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.3.9 + +- Fix a bug in reference counting. +- Optimize `recv_timeout()`. +- Add `Select::remove()`. +- Various small improvements, code cleanup, more tests. + +# Version 0.3.8 + +- Bump the minimum required version of `crossbeam-utils`. + +# Version 0.3.7 + +- Remove `parking_lot` and `rand` dependencies. +- Expand documentation. +- Implement `Default` for `Select`. +- Make `size_of::>()` smaller. +- Several minor optimizations. +- Add more tests. + +# Version 0.3.6 + +- Fix a bug in initialization of unbounded channels. + +# Version 0.3.5 + +- New implementation for unbounded channels. +- A number of small performance improvements. +- Remove `crossbeam-epoch` dependency. + +# Version 0.3.4 + +- Bump `crossbeam-epoch` to `0.7`. +- Improve documentation. + +# Version 0.3.3 + +- Relax the lifetime in `SelectedOperation<'_>`. +- Add `Select::try_ready()`, `Select::ready()`, and `Select::ready_timeout()`. +- Update licensing notices. +- Improve documentation. +- Add methods `is_disconnected()`, `is_timeout()`, `is_empty()`, and `is_full()` on error types. + +# Version 0.3.2 + +- More elaborate licensing notices. + +# Version 0.3.1 + +- Update `crossbeam-utils` to `0.6`. + +# Version 0.3.0 + +- Add a special `never` channel type. +- Dropping all receivers now closes the channel. +- The interface of sending and receiving methods is now very similar to those in v0.1. +- The syntax for `send` in `select!` is now `send(sender, msg) -> res => body`. +- The syntax for `recv` in `select!` is now `recv(receiver) -> res => body`. +- New, more efficient interface for `Select` without callbacks. +- Timeouts can be specified in `select!`. + +# Version 0.2.6 + +- `Select` struct that can add cases dynamically. +- More documentation (in particular, the FAQ section). +- Optimize contended sends/receives in unbounded channels. + +# Version 0.2.5 + +- Use `LocalKey::try_with` instead of `LocalKey::with`. +- Remove helper macros `__crossbeam_channel*`. + +# Version 0.2.4 + +- Make `select!` linearizable with other channel operations. +- Update `crossbeam-utils` to `0.5.0`. +- Update `parking_lot` to `0.6.3`. +- Remove Mac OS X tests. + +# Version 0.2.3 + +- Add Mac OS X tests. +- Lower some memory orderings. +- Eliminate calls to `mem::unitialized`, which caused bugs with ZST. + +# Version 0.2.2 + +- Add more tests. +- Update `crossbeam-epoch` to 0.5.0 +- Initialize the RNG seed to a random value. +- Replace `libc::abort` with `std::process::abort`. +- Ignore clippy warnings in `select!`. +- Better interaction of `select!` with the NLL borrow checker. + +# Version 0.2.1 + +- Fix compilation errors when using `select!` with `#[deny(unsafe_code)]`. + +# Version 0.2.0 + +- Implement `IntoIterator` for `Receiver`. +- Add a new `select!` macro. +- Add special channels `after` and `tick`. +- Dropping receivers doesn't close the channel anymore. +- Change the signature of `recv`, `send`, and `try_recv`. +- Remove `Sender::is_closed` and `Receiver::is_closed`. +- Remove `Sender::close` and `Receiver::close`. +- Remove `Sender::send_timeout` and `Receiver::recv_timeout`. +- Remove `Sender::try_send`. +- Remove `Select` and `select_loop!`. +- Remove all error types. +- Remove `Iter`, `TryIter`, and `IntoIter`. +- Remove the `nightly` feature. +- Remove ordering operators for `Sender` and `Receiver`. + +# Version 0.1.3 + +- Add `Sender::disconnect` and `Receiver::disconnect`. +- Implement comparison operators for `Sender` and `Receiver`. +- Allow arbitrary patterns in place of `msg` in `recv(r, msg)`. +- Add a few conversion impls between error types. +- Add benchmarks for `atomicring` and `mpmc`. +- Add benchmarks for different message sizes. +- Documentation improvements. +- Update `crossbeam-epoch` to 0.4.0 +- Update `crossbeam-utils` to 0.3.0 +- Update `parking_lot` to 0.5 +- Update `rand` to 0.4 + +# Version 0.1.2 + +- Allow conditional cases in `select_loop!` macro. +- Fix typos in documentation. +- Fix deadlock in selection when all channels are disconnected and a timeout is specified. + +# Version 0.1.1 + +- Implement `Debug` for `Sender`, `Receiver`, `Iter`, `TryIter`, `IntoIter`, and `Select`. +- Implement `Default` for `Select`. + +# Version 0.1.0 + +- First implementation of the channels. +- Add `select_loop!` macro by @TimNN. diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/Cargo.lock b/third_party/cargo/vendor/crossbeam-channel-0.5.0/Cargo.lock new file mode 100644 index 0000000..91cb58a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/Cargo.lock @@ -0,0 +1,169 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arc-swap" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const_fn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" + +[[package]] +name = "crossbeam-channel" +version = "0.5.0" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", + "num_cpus", + "rand", + "signal-hook", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "const_fn", + "lazy_static", +] + +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "signal-hook" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +dependencies = [ + "arc-swap", + "libc", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/Cargo.toml b/third_party/cargo/vendor/crossbeam-channel-0.5.0/Cargo.toml new file mode 100644 index 0000000..a5c9964 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "crossbeam-channel" +version = "0.5.0" +authors = ["The Crossbeam Project Developers"] +description = "Multi-producer multi-consumer channels for message passing" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" +documentation = "https://docs.rs/crossbeam-channel" +readme = "README.md" +keywords = ["channel", "mpmc", "select", "golang", "message"] +categories = ["algorithms", "concurrency", "data-structures"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dependencies.cfg-if] +version = "1" + +[dependencies.crossbeam-utils] +version = "0.8" +optional = true +default-features = false +[dev-dependencies.num_cpus] +version = "1.13.0" + +[dev-dependencies.rand] +version = "0.7.3" + +[dev-dependencies.signal-hook] +version = "0.1.15" + +[features] +default = ["std"] +std = ["crossbeam-utils/std"] diff --git a/third_party/cargo/vendor/crossbeam-channel-0.4.2/LICENSE-APACHE b/third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/crossbeam-channel-0.4.2/LICENSE-APACHE rename to third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/LICENSE-MIT b/third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/crossbeam-queue-0.2.2/LICENSE-MIT rename to third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-MIT diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-THIRD-PARTY b/third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-THIRD-PARTY new file mode 100644 index 0000000..d15e32b --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/LICENSE-THIRD-PARTY @@ -0,0 +1,625 @@ +=============================================================================== + +Bounded MPMC queue +http://www.1024cores.net/home/code-license + +Copyright (c) 2010-2011 Dmitry Vyukov. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of Dmitry Vyukov. + +=============================================================================== + +matching.go +https://creativecommons.org/licenses/by/3.0/legalcode + +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at https://creativecommons.org/. + +=============================================================================== + +The Go Programming Language +https://golang.org/LICENSE + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================== + +The Rust Programming Language +https://github.com/rust-lang/rust/blob/master/LICENSE-MIT + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +=============================================================================== + +The Rust Programming Language +https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/README.md b/third_party/cargo/vendor/crossbeam-channel-0.5.0/README.md new file mode 100644 index 0000000..eab623a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/README.md @@ -0,0 +1,88 @@ +# Crossbeam Channel + +[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( +https://github.com/crossbeam-rs/crossbeam/actions) +[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel#license) +[![Cargo](https://img.shields.io/crates/v/crossbeam-channel.svg)]( +https://crates.io/crates/crossbeam-channel) +[![Documentation](https://docs.rs/crossbeam-channel/badge.svg)]( +https://docs.rs/crossbeam-channel) +[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides multi-producer multi-consumer channels for message passing. +It is an alternative to [`std::sync::mpsc`] with more features and better performance. + +Some highlights: + +* [`Sender`]s and [`Receiver`]s can be cloned and shared among threads. +* Two main kinds of channels are [`bounded`] and [`unbounded`]. +* Convenient extra channels like [`after`], [`never`], and [`tick`]. +* The [`select!`] macro can block on multiple channel operations. +* [`Select`] can select over a dynamically built list of channel operations. +* Channels use locks very sparingly for maximum [performance](benchmarks). + +[`std::sync::mpsc`]: https://doc.rust-lang.org/std/sync/mpsc/index.html +[`Sender`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Sender.html +[`Receiver`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Receiver.html +[`bounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.bounded.html +[`unbounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.unbounded.html +[`after`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.after.html +[`never`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.never.html +[`tick`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.tick.html +[`select!`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/macro.select.html +[`Select`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Select.html + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-channel = "0.4" +``` + +## Compatibility + +Crossbeam Channel supports stable Rust releases going back at least six months, +and every time the minimum supported Rust version is increased, a new minor +version is released. Currently, the minimum supported Rust version is 1.36. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +#### Third party software + +This product includes copies and modifications of software developed by third parties: + +* [examples/matching.rs](examples/matching.rs) includes + [matching.go](http://www.nada.kth.se/~snilsson/concurrency/src/matching.go) by Stefan Nilsson, + licensed under Creative Commons Attribution 3.0 Unported License. + +* [src/flavors/array.rs](src/flavors/array.rs) is based on + [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) + by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. + +* [tests/mpsc.rs](tests/mpsc.rs) includes modifications of code from The Rust Programming Language, + licensed under the MIT License and the Apache License, Version 2.0. + +* [tests/golang.rs](tests/golang.rs) is based on code from The Go Programming Language, licensed + under the 3-Clause BSD License. + +See the source code files for more details. + +Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/benches/crossbeam.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/benches/crossbeam.rs new file mode 100644 index 0000000..9870c98 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/benches/crossbeam.rs @@ -0,0 +1,712 @@ +#![feature(test)] + +extern crate test; + +use crossbeam_channel::{bounded, unbounded}; +use crossbeam_utils::thread::scope; +use test::Bencher; + +const TOTAL_STEPS: usize = 40_000; + +mod unbounded { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| unbounded::()); + } + + #[bench] + fn oneshot(b: &mut Bencher) { + b.iter(|| { + let (s, r) = unbounded::(); + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn inout(b: &mut Bencher) { + let (s, r) = unbounded::(); + b.iter(|| { + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn par_inout(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_n { + use super::*; + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(steps); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn par_inout(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + assert_eq!(threads % 2, 0); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_1 { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| bounded::(1)); + } + + #[bench] + fn oneshot(b: &mut Bencher) { + b.iter(|| { + let (s, r) = bounded::(1); + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_0 { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| bounded::(0)); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/fibonacci.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/fibonacci.rs new file mode 100644 index 0000000..cf22b7a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/fibonacci.rs @@ -0,0 +1,25 @@ +//! An asynchronous fibonacci sequence generator. + +use std::thread; + +use crossbeam_channel::{bounded, Sender}; + +// Sends the Fibonacci sequence into the channel until it becomes disconnected. +fn fibonacci(sender: Sender) { + let (mut x, mut y) = (0, 1); + while sender.send(x).is_ok() { + let tmp = x; + x = y; + y = tmp + y; + } +} + +fn main() { + let (s, r) = bounded(0); + thread::spawn(|| fibonacci(s)); + + // Print the first 20 Fibonacci numbers. + for num in r.iter().take(20) { + println!("{}", num); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/matching.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/matching.rs new file mode 100644 index 0000000..5421169 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/matching.rs @@ -0,0 +1,72 @@ +//! Using `select!` to send and receive on the same channel at the same time. +//! +//! This example is based on the following program in Go. +//! +//! Source: +//! - https://web.archive.org/web/20171209034309/https://www.nada.kth.se/~snilsson/concurrency +//! - http://www.nada.kth.se/~snilsson/concurrency/src/matching.go +//! +//! Copyright & License: +//! - Stefan Nilsson +//! - Creative Commons Attribution 3.0 Unported License +//! - https://creativecommons.org/licenses/by/3.0/ +//! +//! ```go +//! func main() { +//! people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"} +//! match := make(chan string, 1) // Make room for one unmatched send. +//! wg := new(sync.WaitGroup) +//! for _, name := range people { +//! wg.Add(1) +//! go Seek(name, match, wg) +//! } +//! wg.Wait() +//! select { +//! case name := <-match: +//! fmt.Printf("No one received %s’s message.\n", name) +//! default: +//! // There was no pending send operation. +//! } +//! } +//! +//! // Seek either sends or receives, whichever possible, a name on the match +//! // channel and notifies the wait group when done. +//! func Seek(name string, match chan string, wg *sync.WaitGroup) { +//! select { +//! case peer := <-match: +//! fmt.Printf("%s received a message from %s.\n", name, peer) +//! case match <- name: +//! // Wait for someone to receive my message. +//! } +//! wg.Done() +//! } +//! ``` + +use crossbeam_channel::{bounded, select}; +use crossbeam_utils::thread; + +fn main() { + let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"]; + let (s, r) = bounded(1); // Make room for one unmatched send. + + // Either send my name into the channel or receive someone else's, whatever happens first. + let seek = |name, s, r| { + select! { + recv(r) -> peer => println!("{} received a message from {}.", name, peer.unwrap()), + send(s, name) -> _ => {}, // Wait for someone to receive my message. + } + }; + + thread::scope(|scope| { + for name in people { + let (s, r) = (s.clone(), r.clone()); + scope.spawn(move |_| seek(name, s, r)); + } + }) + .unwrap(); + + // Check if there is a pending send operation. + if let Ok(name) = r.try_recv() { + println!("No one received {}’s message.", name); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/stopwatch.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/stopwatch.rs new file mode 100644 index 0000000..6a67c9e --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/examples/stopwatch.rs @@ -0,0 +1,60 @@ +//! Prints the elapsed time every 1 second and quits on Ctrl+C. + +#[cfg(windows)] // signal_hook::iterator does not work on windows +fn main() { + println!("This example does not work on Windows"); +} + +#[cfg(not(windows))] +fn main() { + use std::io; + use std::thread; + use std::time::{Duration, Instant}; + + use crossbeam_channel::{bounded, select, tick, Receiver}; + use signal_hook::iterator::Signals; + use signal_hook::SIGINT; + + // Creates a channel that gets a message every time `SIGINT` is signalled. + fn sigint_notifier() -> io::Result> { + let (s, r) = bounded(100); + let signals = Signals::new(&[SIGINT])?; + + thread::spawn(move || { + for _ in signals.forever() { + if s.send(()).is_err() { + break; + } + } + }); + + Ok(r) + } + + // Prints the elapsed time. + fn show(dur: Duration) { + println!( + "Elapsed: {}.{:03} sec", + dur.as_secs(), + dur.subsec_nanos() / 1_000_000 + ); + } + + let start = Instant::now(); + let update = tick(Duration::from_secs(1)); + let ctrl_c = sigint_notifier().unwrap(); + + loop { + select! { + recv(update) -> _ => { + show(start.elapsed()); + } + recv(ctrl_c) -> _ => { + println!(); + println!("Goodbye!"); + show(start.elapsed()); + break; + } + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/channel.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/channel.rs new file mode 100644 index 0000000..ebcd652 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/channel.rs @@ -0,0 +1,1510 @@ +//! The channel interface. + +use std::fmt; +use std::iter::FusedIterator; +use std::mem; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use crate::context::Context; +use crate::counter; +use crate::err::{ + RecvError, RecvTimeoutError, SendError, SendTimeoutError, TryRecvError, TrySendError, +}; +use crate::flavors; +use crate::select::{Operation, SelectHandle, Token}; + +/// Creates a channel of unbounded capacity. +/// +/// This channel has a growable buffer that can hold any number of messages at a time. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// // Computes the n-th Fibonacci number. +/// fn fib(n: i32) -> i32 { +/// if n <= 1 { +/// n +/// } else { +/// fib(n - 1) + fib(n - 2) +/// } +/// } +/// +/// // Spawn an asynchronous computation. +/// thread::spawn(move || s.send(fib(20)).unwrap()); +/// +/// // Print the result of the computation. +/// println!("{}", r.recv().unwrap()); +/// ``` +pub fn unbounded() -> (Sender, Receiver) { + let (s, r) = counter::new(flavors::list::Channel::new()); + let s = Sender { + flavor: SenderFlavor::List(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::List(r), + }; + (s, r) +} + +/// Creates a channel of bounded capacity. +/// +/// This channel has a buffer that can hold at most `cap` messages at a time. +/// +/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and +/// receive operations must appear at the same time in order to pair up and pass the message over. +/// +/// # Examples +/// +/// A channel of capacity 1: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::bounded; +/// +/// let (s, r) = bounded(1); +/// +/// // This call returns immediately because there is enough space in the channel. +/// s.send(1).unwrap(); +/// +/// thread::spawn(move || { +/// // This call blocks the current thread because the channel is full. +/// // It will be able to complete only after the first message is received. +/// s.send(2).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(1)); +/// assert_eq!(r.recv(), Ok(1)); +/// assert_eq!(r.recv(), Ok(2)); +/// ``` +/// +/// A zero-capacity channel: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::bounded; +/// +/// let (s, r) = bounded(0); +/// +/// thread::spawn(move || { +/// // This call blocks the current thread until a receive operation appears +/// // on the other side of the channel. +/// s.send(1).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(1)); +/// assert_eq!(r.recv(), Ok(1)); +/// ``` +pub fn bounded(cap: usize) -> (Sender, Receiver) { + if cap == 0 { + let (s, r) = counter::new(flavors::zero::Channel::new()); + let s = Sender { + flavor: SenderFlavor::Zero(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::Zero(r), + }; + (s, r) + } else { + let (s, r) = counter::new(flavors::array::Channel::with_capacity(cap)); + let s = Sender { + flavor: SenderFlavor::Array(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::Array(r), + }; + (s, r) + } +} + +/// Creates a receiver that delivers a message after a certain duration of time. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Exactly one message will +/// be sent into the channel after `duration` elapses. The message is the instant at which it is +/// sent. +/// +/// # Examples +/// +/// Using an `after` channel for timeouts: +/// +/// ``` +/// use std::time::Duration; +/// use crossbeam_channel::{after, select, unbounded}; +/// +/// let (s, r) = unbounded::(); +/// let timeout = Duration::from_millis(100); +/// +/// select! { +/// recv(r) -> msg => println!("received {:?}", msg), +/// recv(after(timeout)) -> _ => println!("timed out"), +/// } +/// ``` +/// +/// When the message gets sent: +/// +/// ``` +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::after; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// // Returns `true` if `a` and `b` are very close `Instant`s. +/// let eq = |a, b| a + ms(50) > b && b + ms(50) > a; +/// +/// let start = Instant::now(); +/// let r = after(ms(100)); +/// +/// thread::sleep(ms(500)); +/// +/// // This message was sent 100 ms from the start and received 500 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(100))); +/// assert!(eq(Instant::now(), start + ms(500))); +/// ``` +pub fn after(duration: Duration) -> Receiver { + Receiver { + flavor: ReceiverFlavor::At(Arc::new(flavors::at::Channel::new_timeout(duration))), + } +} + +/// Creates a receiver that delivers a message at a certain instant in time. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Exactly one message will +/// be sent into the channel at the moment in time `when`. The message is the instant at which it +/// is sent, which is the same as `when`. If `when` is in the past, the message will be delivered +/// instantly to the receiver. +/// +/// # Examples +/// +/// Using an `at` channel for timeouts: +/// +/// ``` +/// use std::time::{Instant, Duration}; +/// use crossbeam_channel::{at, select, unbounded}; +/// +/// let (s, r) = unbounded::(); +/// let deadline = Instant::now() + Duration::from_millis(500); +/// +/// select! { +/// recv(r) -> msg => println!("received {:?}", msg), +/// recv(at(deadline)) -> _ => println!("timed out"), +/// } +/// ``` +/// +/// When the message gets sent: +/// +/// ``` +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::at; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// let start = Instant::now(); +/// let end = start + ms(100); +/// +/// let r = at(end); +/// +/// // This message was sent 100 ms from the start +/// assert_eq!(r.recv().unwrap(), end); +/// assert!(Instant::now() > start + ms(100)); +/// ``` +pub fn at(when: Instant) -> Receiver { + Receiver { + flavor: ReceiverFlavor::At(Arc::new(flavors::at::Channel::new_deadline(when))), + } +} + +/// Creates a receiver that never delivers messages. +/// +/// The channel is bounded with capacity of 0 and never gets disconnected. +/// +/// # Examples +/// +/// Using a `never` channel to optionally add a timeout to [`select!`]: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::{after, select, never, unbounded}; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s.send(1).unwrap(); +/// }); +/// +/// // Suppose this duration can be a `Some` or a `None`. +/// let duration = Some(Duration::from_millis(100)); +/// +/// // Create a channel that times out after the specified duration. +/// let timeout = duration +/// .map(|d| after(d)) +/// .unwrap_or(never()); +/// +/// select! { +/// recv(r) -> msg => assert_eq!(msg, Ok(1)), +/// recv(timeout) -> _ => println!("timed out"), +/// } +/// ``` +/// +/// [`select!`]: macro.select.html +pub fn never() -> Receiver { + Receiver { + flavor: ReceiverFlavor::Never(flavors::never::Channel::new()), + } +} + +/// Creates a receiver that delivers messages periodically. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Messages will be +/// sent into the channel in intervals of `duration`. Each message is the instant at which it is +/// sent. +/// +/// # Examples +/// +/// Using a `tick` channel to periodically print elapsed time: +/// +/// ``` +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::tick; +/// +/// let start = Instant::now(); +/// let ticker = tick(Duration::from_millis(100)); +/// +/// for _ in 0..5 { +/// ticker.recv().unwrap(); +/// println!("elapsed: {:?}", start.elapsed()); +/// } +/// ``` +/// +/// When messages get sent: +/// +/// ``` +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::tick; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// // Returns `true` if `a` and `b` are very close `Instant`s. +/// let eq = |a, b| a + ms(50) > b && b + ms(50) > a; +/// +/// let start = Instant::now(); +/// let r = tick(ms(100)); +/// +/// // This message was sent 100 ms from the start and received 100 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(100))); +/// assert!(eq(Instant::now(), start + ms(100))); +/// +/// thread::sleep(ms(500)); +/// +/// // This message was sent 200 ms from the start and received 600 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(200))); +/// assert!(eq(Instant::now(), start + ms(600))); +/// +/// // This message was sent 700 ms from the start and received 700 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(700))); +/// assert!(eq(Instant::now(), start + ms(700))); +/// ``` +pub fn tick(duration: Duration) -> Receiver { + Receiver { + flavor: ReceiverFlavor::Tick(Arc::new(flavors::tick::Channel::new(duration))), + } +} + +/// The sending side of a channel. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r) = unbounded(); +/// let s2 = s1.clone(); +/// +/// thread::spawn(move || s1.send(1).unwrap()); +/// thread::spawn(move || s2.send(2).unwrap()); +/// +/// let msg1 = r.recv().unwrap(); +/// let msg2 = r.recv().unwrap(); +/// +/// assert_eq!(msg1 + msg2, 3); +/// ``` +pub struct Sender { + flavor: SenderFlavor, +} + +/// Sender flavors. +enum SenderFlavor { + /// Bounded channel based on a preallocated array. + Array(counter::Sender>), + + /// Unbounded channel implemented as a linked list. + List(counter::Sender>), + + /// Zero-capacity channel. + Zero(counter::Sender>), +} + +unsafe impl Send for Sender {} +unsafe impl Sync for Sender {} + +impl UnwindSafe for Sender {} +impl RefUnwindSafe for Sender {} + +impl Sender { + /// Attempts to send a message into the channel without blocking. + /// + /// This method will either send a message into the channel immediately or return an error if + /// the channel is full or disconnected. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will send the message only if there + /// happens to be a receive operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, TrySendError}; + /// + /// let (s, r) = bounded(1); + /// + /// assert_eq!(s.try_send(1), Ok(())); + /// assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); + /// + /// drop(r); + /// assert_eq!(s.try_send(3), Err(TrySendError::Disconnected(3))); + /// ``` + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.try_send(msg), + SenderFlavor::List(chan) => chan.try_send(msg), + SenderFlavor::Zero(chan) => chan.try_send(msg), + } + } + + /// Blocks the current thread until a message is sent or the channel is disconnected. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed. If the channel becomes disconnected, this call will wake up and return an + /// error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{bounded, SendError}; + /// + /// let (s, r) = bounded(1); + /// assert_eq!(s.send(1), Ok(())); + /// + /// thread::spawn(move || { + /// assert_eq!(r.recv(), Ok(1)); + /// thread::sleep(Duration::from_secs(1)); + /// drop(r); + /// }); + /// + /// assert_eq!(s.send(2), Ok(())); + /// assert_eq!(s.send(3), Err(SendError(3))); + /// ``` + pub fn send(&self, msg: T) -> Result<(), SendError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.send(msg, None), + SenderFlavor::List(chan) => chan.send(msg, None), + SenderFlavor::Zero(chan) => chan.send(msg, None), + } + .map_err(|err| match err { + SendTimeoutError::Disconnected(msg) => SendError(msg), + SendTimeoutError::Timeout(_) => unreachable!(), + }) + } + + /// Waits for a message to be sent into the channel, but only for a limited time. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed or the operation times out. If the channel becomes disconnected, this call will + /// wake up and return an error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{bounded, SendTimeoutError}; + /// + /// let (s, r) = bounded(0); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// assert_eq!(r.recv(), Ok(2)); + /// drop(r); + /// }); + /// + /// assert_eq!( + /// s.send_timeout(1, Duration::from_millis(500)), + /// Err(SendTimeoutError::Timeout(1)), + /// ); + /// assert_eq!( + /// s.send_timeout(2, Duration::from_secs(1)), + /// Ok(()), + /// ); + /// assert_eq!( + /// s.send_timeout(3, Duration::from_millis(500)), + /// Err(SendTimeoutError::Disconnected(3)), + /// ); + /// ``` + pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { + self.send_deadline(msg, Instant::now() + timeout) + } + + /// Waits for a message to be sent into the channel, but only until a given deadline. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed or the operation times out. If the channel becomes disconnected, this call will + /// wake up and return an error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// use crossbeam_channel::{bounded, SendTimeoutError}; + /// + /// let (s, r) = bounded(0); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// assert_eq!(r.recv(), Ok(2)); + /// drop(r); + /// }); + /// + /// let now = Instant::now(); + /// + /// assert_eq!( + /// s.send_deadline(1, now + Duration::from_millis(500)), + /// Err(SendTimeoutError::Timeout(1)), + /// ); + /// assert_eq!( + /// s.send_deadline(2, now + Duration::from_millis(1500)), + /// Ok(()), + /// ); + /// assert_eq!( + /// s.send_deadline(3, now + Duration::from_millis(2000)), + /// Err(SendTimeoutError::Disconnected(3)), + /// ); + /// ``` + pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)), + SenderFlavor::List(chan) => chan.send(msg, Some(deadline)), + SenderFlavor::Zero(chan) => chan.send(msg, Some(deadline)), + } + } + + /// Returns `true` if the channel is empty. + /// + /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert!(s.is_empty()); + /// + /// s.send(0).unwrap(); + /// assert!(!s.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_empty(), + SenderFlavor::List(chan) => chan.is_empty(), + SenderFlavor::Zero(chan) => chan.is_empty(), + } + } + + /// Returns `true` if the channel is full. + /// + /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(1); + /// + /// assert!(!s.is_full()); + /// s.send(0).unwrap(); + /// assert!(s.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_full(), + SenderFlavor::List(chan) => chan.is_full(), + SenderFlavor::Zero(chan) => chan.is_full(), + } + } + + /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(s.len(), 0); + /// + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// assert_eq!(s.len(), 2); + /// ``` + pub fn len(&self) -> usize { + match &self.flavor { + SenderFlavor::Array(chan) => chan.len(), + SenderFlavor::List(chan) => chan.len(), + SenderFlavor::Zero(chan) => chan.len(), + } + } + + /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, unbounded}; + /// + /// let (s, _) = unbounded::(); + /// assert_eq!(s.capacity(), None); + /// + /// let (s, _) = bounded::(5); + /// assert_eq!(s.capacity(), Some(5)); + /// + /// let (s, _) = bounded::(0); + /// assert_eq!(s.capacity(), Some(0)); + /// ``` + pub fn capacity(&self) -> Option { + match &self.flavor { + SenderFlavor::Array(chan) => chan.capacity(), + SenderFlavor::List(chan) => chan.capacity(), + SenderFlavor::Zero(chan) => chan.capacity(), + } + } + + /// Returns `true` if senders belong to the same channel. + /// + /// # Examples + /// + /// ```rust + /// use crossbeam_channel::unbounded; + /// + /// let (s, _) = unbounded::(); + /// + /// let s2 = s.clone(); + /// assert!(s.same_channel(&s2)); + /// + /// let (s3, _) = unbounded(); + /// assert!(!s.same_channel(&s3)); + /// ``` + pub fn same_channel(&self, other: &Sender) -> bool { + match (&self.flavor, &other.flavor) { + (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b, + (SenderFlavor::List(ref a), SenderFlavor::List(ref b)) => a == b, + (SenderFlavor::Zero(ref a), SenderFlavor::Zero(ref b)) => a == b, + _ => false, + } + } +} + +impl Drop for Sender { + fn drop(&mut self) { + unsafe { + match &self.flavor { + SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::List(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()), + } + } + } +} + +impl Clone for Sender { + fn clone(&self) -> Self { + let flavor = match &self.flavor { + SenderFlavor::Array(chan) => SenderFlavor::Array(chan.acquire()), + SenderFlavor::List(chan) => SenderFlavor::List(chan.acquire()), + SenderFlavor::Zero(chan) => SenderFlavor::Zero(chan.acquire()), + }; + + Sender { flavor } + } +} + +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Sender { .. }") + } +} + +/// The receiving side of a channel. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// let _ = s.send(1); +/// thread::sleep(Duration::from_secs(1)); +/// let _ = s.send(2); +/// }); +/// +/// assert_eq!(r.recv(), Ok(1)); // Received immediately. +/// assert_eq!(r.recv(), Ok(2)); // Received after 1 second. +/// ``` +pub struct Receiver { + flavor: ReceiverFlavor, +} + +/// Receiver flavors. +enum ReceiverFlavor { + /// Bounded channel based on a preallocated array. + Array(counter::Receiver>), + + /// Unbounded channel implemented as a linked list. + List(counter::Receiver>), + + /// Zero-capacity channel. + Zero(counter::Receiver>), + + /// The after flavor. + At(Arc), + + /// The tick flavor. + Tick(Arc), + + /// The never flavor. + Never(flavors::never::Channel), +} + +unsafe impl Send for Receiver {} +unsafe impl Sync for Receiver {} + +impl UnwindSafe for Receiver {} +impl RefUnwindSafe for Receiver {} + +impl Receiver { + /// Attempts to receive a message from the channel without blocking. + /// + /// This method will either receive a message from the channel immediately or return an error + /// if the channel is empty. + /// + /// If called on a zero-capacity channel, this method will receive a message only if there + /// happens to be a send operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, TryRecvError}; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + /// + /// s.send(5).unwrap(); + /// drop(s); + /// + /// assert_eq!(r.try_recv(), Ok(5)); + /// assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + /// ``` + pub fn try_recv(&self) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.try_recv(), + ReceiverFlavor::List(chan) => chan.try_recv(), + ReceiverFlavor::Zero(chan) => chan.try_recv(), + ReceiverFlavor::At(chan) => { + let msg = chan.try_recv(); + unsafe { + mem::transmute_copy::, Result>( + &msg, + ) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.try_recv(); + unsafe { + mem::transmute_copy::, Result>( + &msg, + ) + } + } + ReceiverFlavor::Never(chan) => chan.try_recv(), + } + } + + /// Blocks the current thread until a message is received or the channel is empty and + /// disconnected. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed. If the channel is empty and becomes disconnected, this call will + /// wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, RecvError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// assert_eq!(r.recv(), Ok(5)); + /// assert_eq!(r.recv(), Err(RecvError)); + /// ``` + pub fn recv(&self) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.recv(None), + ReceiverFlavor::List(chan) => chan.recv(None), + ReceiverFlavor::Zero(chan) => chan.recv(None), + ReceiverFlavor::At(chan) => { + let msg = chan.recv(None); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.recv(None); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Never(chan) => chan.recv(None), + } + .map_err(|_| RecvError) + } + + /// Waits for a message to be received from the channel, but only for a limited time. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed or the operation times out. If the channel is empty and becomes + /// disconnected, this call will wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, RecvTimeoutError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// assert_eq!( + /// r.recv_timeout(Duration::from_millis(500)), + /// Err(RecvTimeoutError::Timeout), + /// ); + /// assert_eq!( + /// r.recv_timeout(Duration::from_secs(1)), + /// Ok(5), + /// ); + /// assert_eq!( + /// r.recv_timeout(Duration::from_secs(1)), + /// Err(RecvTimeoutError::Disconnected), + /// ); + /// ``` + pub fn recv_timeout(&self, timeout: Duration) -> Result { + self.recv_deadline(Instant::now() + timeout) + } + + /// Waits for a message to be received from the channel, but only before a given deadline. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed or the operation times out. If the channel is empty and becomes + /// disconnected, this call will wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::{Instant, Duration}; + /// use crossbeam_channel::{unbounded, RecvTimeoutError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// let now = Instant::now(); + /// + /// assert_eq!( + /// r.recv_deadline(now + Duration::from_millis(500)), + /// Err(RecvTimeoutError::Timeout), + /// ); + /// assert_eq!( + /// r.recv_deadline(now + Duration::from_millis(1500)), + /// Ok(5), + /// ); + /// assert_eq!( + /// r.recv_deadline(now + Duration::from_secs(5)), + /// Err(RecvTimeoutError::Disconnected), + /// ); + /// ``` + pub fn recv_deadline(&self, deadline: Instant) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::List(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::At(chan) => { + let msg = chan.recv(Some(deadline)); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.recv(Some(deadline)); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Never(chan) => chan.recv(Some(deadline)), + } + } + + /// Returns `true` if the channel is empty. + /// + /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// assert!(r.is_empty()); + /// s.send(0).unwrap(); + /// assert!(!r.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_empty(), + ReceiverFlavor::List(chan) => chan.is_empty(), + ReceiverFlavor::Zero(chan) => chan.is_empty(), + ReceiverFlavor::At(chan) => chan.is_empty(), + ReceiverFlavor::Tick(chan) => chan.is_empty(), + ReceiverFlavor::Never(chan) => chan.is_empty(), + } + } + + /// Returns `true` if the channel is full. + /// + /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(1); + /// + /// assert!(!r.is_full()); + /// s.send(0).unwrap(); + /// assert!(r.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_full(), + ReceiverFlavor::List(chan) => chan.is_full(), + ReceiverFlavor::Zero(chan) => chan.is_full(), + ReceiverFlavor::At(chan) => chan.is_full(), + ReceiverFlavor::Tick(chan) => chan.is_full(), + ReceiverFlavor::Never(chan) => chan.is_full(), + } + } + + /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(r.len(), 0); + /// + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// assert_eq!(r.len(), 2); + /// ``` + pub fn len(&self) -> usize { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.len(), + ReceiverFlavor::List(chan) => chan.len(), + ReceiverFlavor::Zero(chan) => chan.len(), + ReceiverFlavor::At(chan) => chan.len(), + ReceiverFlavor::Tick(chan) => chan.len(), + ReceiverFlavor::Never(chan) => chan.len(), + } + } + + /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, unbounded}; + /// + /// let (_, r) = unbounded::(); + /// assert_eq!(r.capacity(), None); + /// + /// let (_, r) = bounded::(5); + /// assert_eq!(r.capacity(), Some(5)); + /// + /// let (_, r) = bounded::(0); + /// assert_eq!(r.capacity(), Some(0)); + /// ``` + pub fn capacity(&self) -> Option { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.capacity(), + ReceiverFlavor::List(chan) => chan.capacity(), + ReceiverFlavor::Zero(chan) => chan.capacity(), + ReceiverFlavor::At(chan) => chan.capacity(), + ReceiverFlavor::Tick(chan) => chan.capacity(), + ReceiverFlavor::Never(chan) => chan.capacity(), + } + } + + /// A blocking iterator over messages in the channel. + /// + /// Each call to [`next`] blocks waiting for the next message and then returns it. However, if + /// the channel becomes empty and disconnected, it returns [`None`] without blocking. + /// + /// [`next`]: Iterator::next + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// s.send(3).unwrap(); + /// drop(s); // Disconnect the channel. + /// }); + /// + /// // Collect all messages from the channel. + /// // Note that the call to `collect` blocks until the sender is dropped. + /// let v: Vec<_> = r.iter().collect(); + /// + /// assert_eq!(v, [1, 2, 3]); + /// ``` + pub fn iter(&self) -> Iter<'_, T> { + Iter { receiver: self } + } + + /// A non-blocking iterator over messages in the channel. + /// + /// Each call to [`next`] returns a message if there is one ready to be received. The iterator + /// never blocks waiting for the next message. + /// + /// [`next`]: Iterator::next + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded::(); + /// + /// thread::spawn(move || { + /// s.send(1).unwrap(); + /// thread::sleep(Duration::from_secs(1)); + /// s.send(2).unwrap(); + /// thread::sleep(Duration::from_secs(2)); + /// s.send(3).unwrap(); + /// }); + /// + /// thread::sleep(Duration::from_secs(2)); + /// + /// // Collect all messages from the channel without blocking. + /// // The third message hasn't been sent yet so we'll collect only the first two. + /// let v: Vec<_> = r.try_iter().collect(); + /// + /// assert_eq!(v, [1, 2]); + /// ``` + pub fn try_iter(&self) -> TryIter<'_, T> { + TryIter { receiver: self } + } + + /// Returns `true` if receivers belong to the same channel. + /// + /// # Examples + /// + /// ```rust + /// use crossbeam_channel::unbounded; + /// + /// let (_, r) = unbounded::(); + /// + /// let r2 = r.clone(); + /// assert!(r.same_channel(&r2)); + /// + /// let (_, r3) = unbounded(); + /// assert!(!r.same_channel(&r3)); + /// ``` + pub fn same_channel(&self, other: &Receiver) -> bool { + match (&self.flavor, &other.flavor) { + (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b, + (ReceiverFlavor::List(a), ReceiverFlavor::List(b)) => a == b, + (ReceiverFlavor::Zero(a), ReceiverFlavor::Zero(b)) => a == b, + (ReceiverFlavor::At(a), ReceiverFlavor::At(b)) => Arc::ptr_eq(a, b), + (ReceiverFlavor::Tick(a), ReceiverFlavor::Tick(b)) => Arc::ptr_eq(a, b), + (ReceiverFlavor::Never(_), ReceiverFlavor::Never(_)) => true, + _ => false, + } + } +} + +impl Drop for Receiver { + fn drop(&mut self) { + unsafe { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::At(_) => {} + ReceiverFlavor::Tick(_) => {} + ReceiverFlavor::Never(_) => {} + } + } + } +} + +impl Clone for Receiver { + fn clone(&self) -> Self { + let flavor = match &self.flavor { + ReceiverFlavor::Array(chan) => ReceiverFlavor::Array(chan.acquire()), + ReceiverFlavor::List(chan) => ReceiverFlavor::List(chan.acquire()), + ReceiverFlavor::Zero(chan) => ReceiverFlavor::Zero(chan.acquire()), + ReceiverFlavor::At(chan) => ReceiverFlavor::At(chan.clone()), + ReceiverFlavor::Tick(chan) => ReceiverFlavor::Tick(chan.clone()), + ReceiverFlavor::Never(_) => ReceiverFlavor::Never(flavors::never::Channel::new()), + }; + + Receiver { flavor } + } +} + +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Receiver { .. }") + } +} + +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { receiver: self } + } +} + +/// A blocking iterator over messages in a channel. +/// +/// Each call to [`next`] blocks waiting for the next message and then returns it. However, if the +/// channel becomes empty and disconnected, it returns [`None`] without blocking. +/// +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// s.send(2).unwrap(); +/// s.send(3).unwrap(); +/// drop(s); // Disconnect the channel. +/// }); +/// +/// // Collect all messages from the channel. +/// // Note that the call to `collect` blocks until the sender is dropped. +/// let v: Vec<_> = r.iter().collect(); +/// +/// assert_eq!(v, [1, 2, 3]); +/// ``` +pub struct Iter<'a, T> { + receiver: &'a Receiver, +} + +impl FusedIterator for Iter<'_, T> {} + +impl Iterator for Iter<'_, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.recv().ok() + } +} + +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Iter { .. }") + } +} + +/// A non-blocking iterator over messages in a channel. +/// +/// Each call to [`next`] returns a message if there is one ready to be received. The iterator +/// never blocks waiting for the next message. +/// +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded::(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// thread::sleep(Duration::from_secs(1)); +/// s.send(2).unwrap(); +/// thread::sleep(Duration::from_secs(2)); +/// s.send(3).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(2)); +/// +/// // Collect all messages from the channel without blocking. +/// // The third message hasn't been sent yet so we'll collect only the first two. +/// let v: Vec<_> = r.try_iter().collect(); +/// +/// assert_eq!(v, [1, 2]); +/// ``` +pub struct TryIter<'a, T> { + receiver: &'a Receiver, +} + +impl Iterator for TryIter<'_, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.try_recv().ok() + } +} + +impl fmt::Debug for TryIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("TryIter { .. }") + } +} + +/// A blocking iterator over messages in a channel. +/// +/// Each call to [`next`] blocks waiting for the next message and then returns it. However, if the +/// channel becomes empty and disconnected, it returns [`None`] without blocking. +/// +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// s.send(2).unwrap(); +/// s.send(3).unwrap(); +/// drop(s); // Disconnect the channel. +/// }); +/// +/// // Collect all messages from the channel. +/// // Note that the call to `collect` blocks until the sender is dropped. +/// let v: Vec<_> = r.into_iter().collect(); +/// +/// assert_eq!(v, [1, 2, 3]); +/// ``` +pub struct IntoIter { + receiver: Receiver, +} + +impl FusedIterator for IntoIter {} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.recv().ok() + } +} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("IntoIter { .. }") + } +} + +impl SelectHandle for Sender { + fn try_select(&self, token: &mut Token) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().try_select(token), + SenderFlavor::List(chan) => chan.sender().try_select(token), + SenderFlavor::Zero(chan) => chan.sender().try_select(token), + } + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().register(oper, cx), + SenderFlavor::List(chan) => chan.sender().register(oper, cx), + SenderFlavor::Zero(chan) => chan.sender().register(oper, cx), + } + } + + fn unregister(&self, oper: Operation) { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().unregister(oper), + SenderFlavor::List(chan) => chan.sender().unregister(oper), + SenderFlavor::Zero(chan) => chan.sender().unregister(oper), + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().accept(token, cx), + SenderFlavor::List(chan) => chan.sender().accept(token, cx), + SenderFlavor::Zero(chan) => chan.sender().accept(token, cx), + } + } + + fn is_ready(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().is_ready(), + SenderFlavor::List(chan) => chan.sender().is_ready(), + SenderFlavor::Zero(chan) => chan.sender().is_ready(), + } + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().watch(oper, cx), + SenderFlavor::List(chan) => chan.sender().watch(oper, cx), + SenderFlavor::Zero(chan) => chan.sender().watch(oper, cx), + } + } + + fn unwatch(&self, oper: Operation) { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().unwatch(oper), + SenderFlavor::List(chan) => chan.sender().unwatch(oper), + SenderFlavor::Zero(chan) => chan.sender().unwatch(oper), + } + } +} + +impl SelectHandle for Receiver { + fn try_select(&self, token: &mut Token) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().try_select(token), + ReceiverFlavor::List(chan) => chan.receiver().try_select(token), + ReceiverFlavor::Zero(chan) => chan.receiver().try_select(token), + ReceiverFlavor::At(chan) => chan.try_select(token), + ReceiverFlavor::Tick(chan) => chan.try_select(token), + ReceiverFlavor::Never(chan) => chan.try_select(token), + } + } + + fn deadline(&self) -> Option { + match &self.flavor { + ReceiverFlavor::Array(_) => None, + ReceiverFlavor::List(_) => None, + ReceiverFlavor::Zero(_) => None, + ReceiverFlavor::At(chan) => chan.deadline(), + ReceiverFlavor::Tick(chan) => chan.deadline(), + ReceiverFlavor::Never(chan) => chan.deadline(), + } + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::List(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::At(chan) => chan.register(oper, cx), + ReceiverFlavor::Tick(chan) => chan.register(oper, cx), + ReceiverFlavor::Never(chan) => chan.register(oper, cx), + } + } + + fn unregister(&self, oper: Operation) { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::List(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::Zero(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::At(chan) => chan.unregister(oper), + ReceiverFlavor::Tick(chan) => chan.unregister(oper), + ReceiverFlavor::Never(chan) => chan.unregister(oper), + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::List(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::At(chan) => chan.accept(token, cx), + ReceiverFlavor::Tick(chan) => chan.accept(token, cx), + ReceiverFlavor::Never(chan) => chan.accept(token, cx), + } + } + + fn is_ready(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().is_ready(), + ReceiverFlavor::List(chan) => chan.receiver().is_ready(), + ReceiverFlavor::Zero(chan) => chan.receiver().is_ready(), + ReceiverFlavor::At(chan) => chan.is_ready(), + ReceiverFlavor::Tick(chan) => chan.is_ready(), + ReceiverFlavor::Never(chan) => chan.is_ready(), + } + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::List(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::At(chan) => chan.watch(oper, cx), + ReceiverFlavor::Tick(chan) => chan.watch(oper, cx), + ReceiverFlavor::Never(chan) => chan.watch(oper, cx), + } + } + + fn unwatch(&self, oper: Operation) { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::List(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::Zero(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::At(chan) => chan.unwatch(oper), + ReceiverFlavor::Tick(chan) => chan.unwatch(oper), + ReceiverFlavor::Never(chan) => chan.unwatch(oper), + } + } +} + +/// Writes a message into the channel. +pub unsafe fn write(s: &Sender, token: &mut Token, msg: T) -> Result<(), T> { + match &s.flavor { + SenderFlavor::Array(chan) => chan.write(token, msg), + SenderFlavor::List(chan) => chan.write(token, msg), + SenderFlavor::Zero(chan) => chan.write(token, msg), + } +} + +/// Reads a message from the channel. +pub unsafe fn read(r: &Receiver, token: &mut Token) -> Result { + match &r.flavor { + ReceiverFlavor::Array(chan) => chan.read(token), + ReceiverFlavor::List(chan) => chan.read(token), + ReceiverFlavor::Zero(chan) => chan.read(token), + ReceiverFlavor::At(chan) => { + mem::transmute_copy::, Result>(&chan.read(token)) + } + ReceiverFlavor::Tick(chan) => { + mem::transmute_copy::, Result>(&chan.read(token)) + } + ReceiverFlavor::Never(chan) => chan.read(token), + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/context.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/context.rs new file mode 100644 index 0000000..e2e8480 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/context.rs @@ -0,0 +1,191 @@ +//! Thread-local context used in select. + +use std::cell::Cell; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread::{self, Thread, ThreadId}; +use std::time::Instant; + +use crossbeam_utils::Backoff; + +use crate::select::Selected; + +/// Thread-local context used in select. +#[derive(Debug, Clone)] +pub struct Context { + inner: Arc, +} + +/// Inner representation of `Context`. +#[derive(Debug)] +struct Inner { + /// Selected operation. + select: AtomicUsize, + + /// A slot into which another thread may store a pointer to its `Packet`. + packet: AtomicUsize, + + /// Thread handle. + thread: Thread, + + /// Thread id. + thread_id: ThreadId, +} + +impl Context { + /// Creates a new context for the duration of the closure. + #[inline] + pub fn with(f: F) -> R + where + F: FnOnce(&Context) -> R, + { + thread_local! { + /// Cached thread-local context. + static CONTEXT: Cell> = Cell::new(Some(Context::new())); + } + + let mut f = Some(f); + let mut f = move |cx: &Context| -> R { + let f = f.take().unwrap(); + f(cx) + }; + + CONTEXT + .try_with(|cell| match cell.take() { + None => f(&Context::new()), + Some(cx) => { + cx.reset(); + let res = f(&cx); + cell.set(Some(cx)); + res + } + }) + .unwrap_or_else(|_| f(&Context::new())) + } + + /// Creates a new `Context`. + #[cold] + fn new() -> Context { + Context { + inner: Arc::new(Inner { + select: AtomicUsize::new(Selected::Waiting.into()), + packet: AtomicUsize::new(0), + thread: thread::current(), + thread_id: thread::current().id(), + }), + } + } + + /// Resets `select` and `packet`. + #[inline] + fn reset(&self) { + self.inner + .select + .store(Selected::Waiting.into(), Ordering::Release); + self.inner.packet.store(0, Ordering::Release); + } + + /// Attempts to select an operation. + /// + /// On failure, the previously selected operation is returned. + #[inline] + pub fn try_select(&self, select: Selected) -> Result<(), Selected> { + self.inner + .select + .compare_exchange( + Selected::Waiting.into(), + select.into(), + Ordering::AcqRel, + Ordering::Acquire, + ) + .map(|_| ()) + .map_err(|e| e.into()) + } + + /// Returns the selected operation. + #[inline] + pub fn selected(&self) -> Selected { + Selected::from(self.inner.select.load(Ordering::Acquire)) + } + + /// Stores a packet. + /// + /// This method must be called after `try_select` succeeds and there is a packet to provide. + #[inline] + pub fn store_packet(&self, packet: usize) { + if packet != 0 { + self.inner.packet.store(packet, Ordering::Release); + } + } + + /// Waits until a packet is provided and returns it. + #[inline] + pub fn wait_packet(&self) -> usize { + let backoff = Backoff::new(); + loop { + let packet = self.inner.packet.load(Ordering::Acquire); + if packet != 0 { + return packet; + } + backoff.snooze(); + } + } + + /// Waits until an operation is selected and returns it. + /// + /// If the deadline is reached, `Selected::Aborted` will be selected. + #[inline] + pub fn wait_until(&self, deadline: Option) -> Selected { + // Spin for a short time, waiting until an operation is selected. + let backoff = Backoff::new(); + loop { + let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); + if sel != Selected::Waiting { + return sel; + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + loop { + // Check whether an operation has been selected. + let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); + if sel != Selected::Waiting { + return sel; + } + + // If there's a deadline, park the current thread until the deadline is reached. + if let Some(end) = deadline { + let now = Instant::now(); + + if now < end { + thread::park_timeout(end - now); + } else { + // The deadline has been reached. Try aborting select. + return match self.try_select(Selected::Aborted) { + Ok(()) => Selected::Aborted, + Err(s) => s, + }; + } + } else { + thread::park(); + } + } + } + + /// Unparks the thread this context belongs to. + #[inline] + pub fn unpark(&self) { + self.inner.thread.unpark(); + } + + /// Returns the id of the thread this context belongs to. + #[inline] + pub fn thread_id(&self) -> ThreadId { + self.inner.thread_id + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/counter.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/counter.rs new file mode 100644 index 0000000..2eaf067 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/counter.rs @@ -0,0 +1,144 @@ +//! Reference counter for channels. + +use std::isize; +use std::ops; +use std::process; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + +/// Reference counter internals. +struct Counter { + /// The number of senders associated with the channel. + senders: AtomicUsize, + + /// The number of receivers associated with the channel. + receivers: AtomicUsize, + + /// Set to `true` if the last sender or the last receiver reference deallocates the channel. + destroy: AtomicBool, + + /// The internal channel. + chan: C, +} + +/// Wraps a channel into the reference counter. +pub fn new(chan: C) -> (Sender, Receiver) { + let counter = Box::into_raw(Box::new(Counter { + senders: AtomicUsize::new(1), + receivers: AtomicUsize::new(1), + destroy: AtomicBool::new(false), + chan, + })); + let s = Sender { counter }; + let r = Receiver { counter }; + (s, r) +} + +/// The sending side. +pub struct Sender { + counter: *mut Counter, +} + +impl Sender { + /// Returns the internal `Counter`. + fn counter(&self) -> &Counter { + unsafe { &*self.counter } + } + + /// Acquires another sender reference. + pub fn acquire(&self) -> Sender { + let count = self.counter().senders.fetch_add(1, Ordering::Relaxed); + + // Cloning senders and calling `mem::forget` on the clones could potentially overflow the + // counter. It's very difficult to recover sensibly from such degenerate scenarios so we + // just abort when the count becomes very large. + if count > isize::MAX as usize { + process::abort(); + } + + Sender { + counter: self.counter, + } + } + + /// Releases the sender reference. + /// + /// Function `disconnect` will be called if this is the last sender reference. + pub unsafe fn release bool>(&self, disconnect: F) { + if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 { + disconnect(&self.counter().chan); + + if self.counter().destroy.swap(true, Ordering::AcqRel) { + drop(Box::from_raw(self.counter)); + } + } + } +} + +impl ops::Deref for Sender { + type Target = C; + + fn deref(&self) -> &C { + &self.counter().chan + } +} + +impl PartialEq for Sender { + fn eq(&self, other: &Sender) -> bool { + self.counter == other.counter + } +} + +/// The receiving side. +pub struct Receiver { + counter: *mut Counter, +} + +impl Receiver { + /// Returns the internal `Counter`. + fn counter(&self) -> &Counter { + unsafe { &*self.counter } + } + + /// Acquires another receiver reference. + pub fn acquire(&self) -> Receiver { + let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed); + + // Cloning receivers and calling `mem::forget` on the clones could potentially overflow the + // counter. It's very difficult to recover sensibly from such degenerate scenarios so we + // just abort when the count becomes very large. + if count > isize::MAX as usize { + process::abort(); + } + + Receiver { + counter: self.counter, + } + } + + /// Releases the receiver reference. + /// + /// Function `disconnect` will be called if this is the last receiver reference. + pub unsafe fn release bool>(&self, disconnect: F) { + if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 { + disconnect(&self.counter().chan); + + if self.counter().destroy.swap(true, Ordering::AcqRel) { + drop(Box::from_raw(self.counter)); + } + } + } +} + +impl ops::Deref for Receiver { + type Target = C; + + fn deref(&self) -> &C { + &self.counter().chan + } +} + +impl PartialEq for Receiver { + fn eq(&self, other: &Receiver) -> bool { + self.counter == other.counter + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/err.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/err.rs new file mode 100644 index 0000000..578acc6 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/err.rs @@ -0,0 +1,382 @@ +use std::error; +use std::fmt; + +/// An error returned from the [`send`] method. +/// +/// The message could not be sent because the channel is disconnected. +/// +/// The error contains the message so it can be recovered. +/// +/// [`send`]: super::Sender::send +#[derive(PartialEq, Eq, Clone, Copy)] +pub struct SendError(pub T); + +/// An error returned from the [`try_send`] method. +/// +/// The error contains the message being sent so it can be recovered. +/// +/// [`try_send`]: super::Sender::try_send +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum TrySendError { + /// The message could not be sent because the channel is full. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no receiver + /// available to receive the message at the time. + Full(T), + + /// The message could not be sent because the channel is disconnected. + Disconnected(T), +} + +/// An error returned from the [`send_timeout`] method. +/// +/// The error contains the message being sent so it can be recovered. +/// +/// [`send_timeout`]: super::Sender::send_timeout +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum SendTimeoutError { + /// The message could not be sent because the channel is full and the operation timed out. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no receiver + /// available to receive the message and the operation timed out. + Timeout(T), + + /// The message could not be sent because the channel is disconnected. + Disconnected(T), +} + +/// An error returned from the [`recv`] method. +/// +/// A message could not be received because the channel is empty and disconnected. +/// +/// [`recv`]: super::Receiver::recv +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct RecvError; + +/// An error returned from the [`try_recv`] method. +/// +/// [`try_recv`]: super::Receiver::try_recv +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum TryRecvError { + /// A message could not be received because the channel is empty. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no sender + /// available to send a message at the time. + Empty, + + /// The message could not be received because the channel is empty and disconnected. + Disconnected, +} + +/// An error returned from the [`recv_timeout`] method. +/// +/// [`recv_timeout`]: super::Receiver::recv_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RecvTimeoutError { + /// A message could not be received because the channel is empty and the operation timed out. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no sender + /// available to send a message and the operation timed out. + Timeout, + + /// The message could not be received because the channel is empty and disconnected. + Disconnected, +} + +/// An error returned from the [`try_select`] method. +/// +/// Failed because none of the channel operations were ready. +/// +/// [`try_select`]: super::Select::try_select +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct TrySelectError; + +/// An error returned from the [`select_timeout`] method. +/// +/// Failed because none of the channel operations became ready before the timeout. +/// +/// [`select_timeout`]: super::Select::select_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct SelectTimeoutError; + +/// An error returned from the [`try_ready`] method. +/// +/// Failed because none of the channel operations were ready. +/// +/// [`try_ready`]: super::Select::try_ready +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct TryReadyError; + +/// An error returned from the [`ready_timeout`] method. +/// +/// Failed because none of the channel operations became ready before the timeout. +/// +/// [`ready_timeout`]: super::Select::ready_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ReadyTimeoutError; + +impl fmt::Debug for SendError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "SendError(..)".fmt(f) + } +} + +impl fmt::Display for SendError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "sending on a disconnected channel".fmt(f) + } +} + +impl error::Error for SendError {} + +impl SendError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// drop(r); + /// + /// if let Err(err) = s.send("foo") { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + self.0 + } +} + +impl fmt::Debug for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TrySendError::Full(..) => "Full(..)".fmt(f), + TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + } + } +} + +impl fmt::Display for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TrySendError::Full(..) => "sending on a full channel".fmt(f), + TrySendError::Disconnected(..) => "sending on a disconnected channel".fmt(f), + } + } +} + +impl error::Error for TrySendError {} + +impl From> for TrySendError { + fn from(err: SendError) -> TrySendError { + match err { + SendError(t) => TrySendError::Disconnected(t), + } + } +} + +impl TrySendError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(0); + /// + /// if let Err(err) = s.try_send("foo") { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + match self { + TrySendError::Full(v) => v, + TrySendError::Disconnected(v) => v, + } + } + + /// Returns `true` if the send operation failed because the channel is full. + pub fn is_full(&self) -> bool { + match self { + TrySendError::Full(_) => true, + _ => false, + } + } + + /// Returns `true` if the send operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + TrySendError::Disconnected(_) => true, + _ => false, + } + } +} + +impl fmt::Debug for SendTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "SendTimeoutError(..)".fmt(f) + } +} + +impl fmt::Display for SendTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f), + SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f), + } + } +} + +impl error::Error for SendTimeoutError {} + +impl From> for SendTimeoutError { + fn from(err: SendError) -> SendTimeoutError { + match err { + SendError(e) => SendTimeoutError::Disconnected(e), + } + } +} + +impl SendTimeoutError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// if let Err(err) = s.send_timeout("foo", Duration::from_secs(1)) { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + match self { + SendTimeoutError::Timeout(v) => v, + SendTimeoutError::Disconnected(v) => v, + } + } + + /// Returns `true` if the send operation timed out. + pub fn is_timeout(&self) -> bool { + match self { + SendTimeoutError::Timeout(_) => true, + _ => false, + } + } + + /// Returns `true` if the send operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + SendTimeoutError::Disconnected(_) => true, + _ => false, + } + } +} + +impl fmt::Display for RecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "receiving on an empty and disconnected channel".fmt(f) + } +} + +impl error::Error for RecvError {} + +impl fmt::Display for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TryRecvError::Empty => "receiving on an empty channel".fmt(f), + TryRecvError::Disconnected => "receiving on an empty and disconnected channel".fmt(f), + } + } +} + +impl error::Error for TryRecvError {} + +impl From for TryRecvError { + fn from(err: RecvError) -> TryRecvError { + match err { + RecvError => TryRecvError::Disconnected, + } + } +} + +impl TryRecvError { + /// Returns `true` if the receive operation failed because the channel is empty. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn is_empty(&self) -> bool { + match self { + TryRecvError::Empty => true, + _ => false, + } + } + + /// Returns `true` if the receive operation failed because the channel is disconnected. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn is_disconnected(&self) -> bool { + match self { + TryRecvError::Disconnected => true, + _ => false, + } + } +} + +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout => "timed out waiting on receive operation".fmt(f), + RecvTimeoutError::Disconnected => "channel is empty and disconnected".fmt(f), + } + } +} + +impl error::Error for RecvTimeoutError {} + +impl From for RecvTimeoutError { + fn from(err: RecvError) -> RecvTimeoutError { + match err { + RecvError => RecvTimeoutError::Disconnected, + } + } +} + +impl RecvTimeoutError { + /// Returns `true` if the receive operation timed out. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn is_timeout(&self) -> bool { + match self { + RecvTimeoutError::Timeout => true, + _ => false, + } + } + + /// Returns `true` if the receive operation failed because the channel is disconnected. + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn is_disconnected(&self) -> bool { + match self { + RecvTimeoutError::Disconnected => true, + _ => false, + } + } +} + +impl fmt::Display for TrySelectError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "all operations in select would block".fmt(f) + } +} + +impl error::Error for TrySelectError {} + +impl fmt::Display for SelectTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "timed out waiting on select".fmt(f) + } +} + +impl error::Error for SelectTimeoutError {} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/array.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/array.rs new file mode 100644 index 0000000..323a200 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/array.rs @@ -0,0 +1,641 @@ +//! Bounded channel based on a preallocated array. +//! +//! This flavor has a fixed, positive capacity. +//! +//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. +//! +//! Source: +//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue +//! - https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub +//! +//! Copyright & License: +//! - Copyright (c) 2010-2011 Dmitry Vyukov +//! - Simplified BSD License and Apache License, Version 2.0 +//! - http://www.1024cores.net/home/code-license + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::mem::{self, MaybeUninit}; +use std::ptr; +use std::sync::atomic::{self, AtomicUsize, Ordering}; +use std::time::Instant; + +use crossbeam_utils::{Backoff, CachePadded}; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use crate::select::{Operation, SelectHandle, Selected, Token}; +use crate::waker::SyncWaker; + +/// A slot in a channel. +struct Slot { + /// The current stamp. + stamp: AtomicUsize, + + /// The message in this slot. + msg: UnsafeCell>, +} + +/// The token type for the array flavor. +#[derive(Debug)] +pub struct ArrayToken { + /// Slot to read from or write to. + slot: *const u8, + + /// Stamp to store into the slot after reading or writing. + stamp: usize, +} + +impl Default for ArrayToken { + #[inline] + fn default() -> Self { + ArrayToken { + slot: ptr::null(), + stamp: 0, + } + } +} + +/// Bounded channel based on a preallocated array. +pub struct Channel { + /// The head of the channel. + /// + /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but + /// packed into a single `usize`. The lower bits represent the index, while the upper bits + /// represent the lap. The mark bit in the head is always zero. + /// + /// Messages are popped from the head of the channel. + head: CachePadded, + + /// The tail of the channel. + /// + /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but + /// packed into a single `usize`. The lower bits represent the index, while the upper bits + /// represent the lap. The mark bit indicates that the channel is disconnected. + /// + /// Messages are pushed into the tail of the channel. + tail: CachePadded, + + /// The buffer holding slots. + buffer: *mut Slot, + + /// The channel capacity. + cap: usize, + + /// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`. + one_lap: usize, + + /// If this bit is set in the tail, that means the channel is disconnected. + mark_bit: usize, + + /// Senders waiting while the channel is full. + senders: SyncWaker, + + /// Receivers waiting while the channel is empty and not disconnected. + receivers: SyncWaker, + + /// Indicates that dropping a `Channel` may drop values of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Creates a bounded channel of capacity `cap`. + pub fn with_capacity(cap: usize) -> Self { + assert!(cap > 0, "capacity must be positive"); + + // Compute constants `mark_bit` and `one_lap`. + let mark_bit = (cap + 1).next_power_of_two(); + let one_lap = mark_bit * 2; + + // Head is initialized to `{ lap: 0, mark: 0, index: 0 }`. + let head = 0; + // Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`. + let tail = 0; + + // Allocate a buffer of `cap` slots initialized + // with stamps. + let buffer = { + let mut boxed: Box<[Slot]> = (0..cap) + .map(|i| { + // Set the stamp to `{ lap: 0, mark: 0, index: i }`. + Slot { + stamp: AtomicUsize::new(i), + msg: UnsafeCell::new(MaybeUninit::uninit()), + } + }) + .collect(); + let ptr = boxed.as_mut_ptr(); + mem::forget(boxed); + ptr + }; + + Channel { + buffer, + cap, + one_lap, + mark_bit, + head: CachePadded::new(AtomicUsize::new(head)), + tail: CachePadded::new(AtomicUsize::new(tail)), + senders: SyncWaker::new(), + receivers: SyncWaker::new(), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver<'_, T> { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender<'_, T> { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut tail = self.tail.load(Ordering::Relaxed); + + loop { + // Check if the channel is disconnected. + if tail & self.mark_bit != 0 { + token.array.slot = ptr::null(); + token.array.stamp = 0; + return true; + } + + // Deconstruct the tail. + let index = tail & (self.mark_bit - 1); + let lap = tail & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the tail and the stamp match, we may attempt to push. + if tail == stamp { + let new_tail = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + tail + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the tail. + match self.tail.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Prepare the token for the follow-up call to `write`. + token.array.slot = slot as *const Slot as *const u8; + token.array.stamp = tail + 1; + return true; + } + Err(t) => { + tail = t; + backoff.spin(); + } + } + } else if stamp.wrapping_add(self.one_lap) == tail + 1 { + atomic::fence(Ordering::SeqCst); + let head = self.head.load(Ordering::Relaxed); + + // If the head lags one lap behind the tail as well... + if head.wrapping_add(self.one_lap) == tail { + // ...then the channel is full. + return false; + } + + backoff.spin(); + tail = self.tail.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + tail = self.tail.load(Ordering::Relaxed); + } + } + } + + /// Writes a message into the channel. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no slot, the channel is disconnected. + if token.array.slot.is_null() { + return Err(msg); + } + + let slot: &Slot = &*(token.array.slot as *const Slot); + + // Write the message into the slot and update the stamp. + slot.msg.get().write(MaybeUninit::new(msg)); + slot.stamp.store(token.array.stamp, Ordering::Release); + + // Wake a sleeping receiver. + self.receivers.notify(); + Ok(()) + } + + /// Attempts to reserve a slot for receiving a message. + fn start_recv(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut head = self.head.load(Ordering::Relaxed); + + loop { + // Deconstruct the head. + let index = head & (self.mark_bit - 1); + let lap = head & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the the stamp is ahead of the head by 1, we may attempt to pop. + if head + 1 == stamp { + let new = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the head. + match self.head.compare_exchange_weak( + head, + new, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Prepare the token for the follow-up call to `read`. + token.array.slot = slot as *const Slot as *const u8; + token.array.stamp = head.wrapping_add(self.one_lap); + return true; + } + Err(h) => { + head = h; + backoff.spin(); + } + } + } else if stamp == head { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.load(Ordering::Relaxed); + + // If the tail equals the head, that means the channel is empty. + if (tail & !self.mark_bit) == head { + // If the channel is disconnected... + if tail & self.mark_bit != 0 { + // ...then receive an error. + token.array.slot = ptr::null(); + token.array.stamp = 0; + return true; + } else { + // Otherwise, the receive operation is not ready. + return false; + } + } + + backoff.spin(); + head = self.head.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + head = self.head.load(Ordering::Relaxed); + } + } + } + + /// Reads a message from the channel. + pub unsafe fn read(&self, token: &mut Token) -> Result { + if token.array.slot.is_null() { + // The channel is disconnected. + return Err(()); + } + + let slot: &Slot = &*(token.array.slot as *const Slot); + + // Read the message from the slot and update the stamp. + let msg = slot.msg.get().read().assume_init(); + slot.stamp.store(token.array.stamp, Ordering::Release); + + // Wake a sleeping sender. + self.senders.notify(); + Ok(msg) + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + let token = &mut Token::default(); + if self.start_send(token) { + unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) } + } else { + Err(TrySendError::Full(msg)) + } + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + loop { + // Try sending a message several times. + let backoff = Backoff::new(); + loop { + if self.start_send(token) { + let res = unsafe { self.write(token, msg) }; + return res.map_err(SendTimeoutError::Disconnected); + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(SendTimeoutError::Timeout(msg)); + } + } + + Context::with(|cx| { + // Prepare for blocking until a receiver wakes us up. + let oper = Operation::hook(token); + self.senders.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_full() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.senders.unregister(oper).unwrap(); + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + + if self.start_recv(token) { + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + loop { + // Try receiving a message several times. + let backoff = Backoff::new(); + loop { + if self.start_recv(token) { + let res = unsafe { self.read(token) }; + return res.map_err(|_| RecvTimeoutError::Disconnected); + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(RecvTimeoutError::Timeout); + } + } + + Context::with(|cx| { + // Prepare for blocking until a sender wakes us up. + let oper = Operation::hook(token); + self.receivers.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_empty() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.receivers.unregister(oper).unwrap(); + // If the channel was disconnected, we still have to check for remaining + // messages. + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + loop { + // Load the tail, then load the head. + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // If the tail didn't change, we've got consistent values to work with. + if self.tail.load(Ordering::SeqCst) == tail { + let hix = head & (self.mark_bit - 1); + let tix = tail & (self.mark_bit - 1); + + return if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if (tail & !self.mark_bit) == head { + 0 + } else { + self.cap + }; + } + } + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + Some(self.cap) + } + + /// Disconnects the channel and wakes up all blocked senders and receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); + + if tail & self.mark_bit == 0 { + self.senders.disconnect(); + self.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns `true` if the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + self.tail.load(Ordering::SeqCst) & self.mark_bit != 0 + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + let head = self.head.load(Ordering::SeqCst); + let tail = self.tail.load(Ordering::SeqCst); + + // Is the tail equal to the head? + // + // Note: If the head changes just before we load the tail, that means there was a moment + // when the channel was not empty, so it is safe to just return `false`. + (tail & !self.mark_bit) == head + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // Is the head lagging one lap behind tail? + // + // Note: If the tail changes just before we load the head, that means there was a moment + // when the channel was not full, so it is safe to just return `false`. + head.wrapping_add(self.one_lap) == tail & !self.mark_bit + } +} + +impl Drop for Channel { + fn drop(&mut self) { + // Get the index of the head. + let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1); + + // Loop over all slots that hold a message and drop them. + for i in 0..self.len() { + // Compute the index of the next slot holding a message. + let index = if hix + i < self.cap { + hix + i + } else { + hix + i - self.cap + }; + + unsafe { + let p = { + let slot = &mut *self.buffer.add(index); + let msg = &mut *slot.msg.get(); + msg.as_mut_ptr() + }; + p.drop_in_place(); + } + } + + // Finally, deallocate the buffer, but don't run any destructors. + unsafe { + // Create a slice from the buffer to make + // a fat pointer. Then, use Box::from_raw + // to deallocate it. + let ptr = std::slice::from_raw_parts_mut(self.buffer, self.cap) as *mut [Slot]; + Box::from_raw(ptr); + } + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T>(&'a Channel); + +impl SelectHandle for Receiver<'_, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.receivers.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_empty() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.receivers.unwatch(oper); + } +} + +impl SelectHandle for Sender<'_, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.senders.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.senders.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_full() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.senders.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.senders.unwatch(oper); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/at.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/at.rs new file mode 100644 index 0000000..a2b1b57 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/at.rs @@ -0,0 +1,202 @@ +//! Channel that delivers a message at a certain moment in time. +//! +//! Messages cannot be sent into this kind of channel; they are materialized on demand. + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, TryRecvError}; +use crate::select::{Operation, SelectHandle, Token}; +use crate::utils; + +/// Result of a receive operation. +pub type AtToken = Option; + +/// Channel that delivers a message at a certain moment in time +pub struct Channel { + /// The instant at which the message will be delivered. + delivery_time: Instant, + + /// `true` if the message has been received. + received: AtomicBool, +} + +impl Channel { + /// Creates a channel that delivers a message at a certain instant in time. + #[inline] + pub fn new_deadline(when: Instant) -> Self { + Channel { + delivery_time: when, + received: AtomicBool::new(false), + } + } + /// Creates a channel that delivers a message after a certain duration of time. + #[inline] + pub fn new_timeout(dur: Duration) -> Self { + Self::new_deadline(Instant::now() + dur) + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + // The message has already been received. + return Err(TryRecvError::Empty); + } + + if Instant::now() < self.delivery_time { + // The message was not delivered yet. + return Err(TryRecvError::Empty); + } + + // Try receiving the message if it is still available. + if !self.received.swap(true, Ordering::SeqCst) { + // Success! Return delivery time as the message. + Ok(self.delivery_time) + } else { + // The message was already received. + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + // The message has already been received. + utils::sleep_until(deadline); + return Err(RecvTimeoutError::Timeout); + } + + // Wait until the message is received or the deadline is reached. + loop { + let now = Instant::now(); + + let deadline = match deadline { + // Check if we can receive the next message. + _ if now >= self.delivery_time => break, + // Check if the timeout deadline has been reached. + Some(d) if now >= d => return Err(RecvTimeoutError::Timeout), + + // Sleep until one of the above happens + Some(d) if d < self.delivery_time => d, + _ => self.delivery_time, + }; + + thread::sleep(deadline - now); + } + + // Try receiving the message if it is still available. + if !self.received.swap(true, Ordering::SeqCst) { + // Success! Return the message, which is the instant at which it was delivered. + Ok(self.delivery_time) + } else { + // The message was already received. Block forever. + utils::sleep_until(None); + unreachable!() + } + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, token: &mut Token) -> Result { + token.at.ok_or(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + return true; + } + + // If the delivery time hasn't been reached yet, the channel is empty. + if Instant::now() < self.delivery_time { + return true; + } + + // The delivery time has been reached. The channel is empty only if the message has already + // been received. + self.received.load(Ordering::SeqCst) + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + if self.is_empty() { + 0 + } else { + 1 + } + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(1) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, token: &mut Token) -> bool { + match self.try_recv() { + Ok(msg) => { + token.at = Some(msg); + true + } + Err(TryRecvError::Disconnected) => { + token.at = None; + true + } + Err(TryRecvError::Empty) => false, + } + } + + #[inline] + fn deadline(&self) -> Option { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + None + } else { + Some(self.delivery_time) + } + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + !self.is_empty() + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/list.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/list.rs new file mode 100644 index 0000000..532e8b6 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/list.rs @@ -0,0 +1,669 @@ +//! Unbounded channel implemented as a linked list. + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::mem::MaybeUninit; +use std::ptr; +use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; +use std::time::Instant; + +use crossbeam_utils::{Backoff, CachePadded}; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use crate::select::{Operation, SelectHandle, Selected, Token}; +use crate::waker::SyncWaker; + +// TODO(stjepang): Once we bump the minimum required Rust version to 1.28 or newer, re-apply the +// following changes by @kleimkuhler: +// +// 1. https://github.com/crossbeam-rs/crossbeam-channel/pull/100 +// 2. https://github.com/crossbeam-rs/crossbeam-channel/pull/101 + +// Bits indicating the state of a slot: +// * If a message has been written into the slot, `WRITE` is set. +// * If a message has been read from the slot, `READ` is set. +// * If the block is being destroyed, `DESTROY` is set. +const WRITE: usize = 1; +const READ: usize = 2; +const DESTROY: usize = 4; + +// Each block covers one "lap" of indices. +const LAP: usize = 32; +// The maximum number of messages a block can hold. +const BLOCK_CAP: usize = LAP - 1; +// How many lower bits are reserved for metadata. +const SHIFT: usize = 1; +// Has two different purposes: +// * If set in head, indicates that the block is not the last one. +// * If set in tail, indicates that the channel is disconnected. +const MARK_BIT: usize = 1; + +/// A slot in a block. +struct Slot { + /// The message. + msg: UnsafeCell>, + + /// The state of the slot. + state: AtomicUsize, +} + +impl Slot { + /// Waits until a message is written into the slot. + fn wait_write(&self) { + let backoff = Backoff::new(); + while self.state.load(Ordering::Acquire) & WRITE == 0 { + backoff.snooze(); + } + } +} + +/// A block in a linked list. +/// +/// Each block in the list can hold up to `BLOCK_CAP` messages. +struct Block { + /// The next block in the linked list. + next: AtomicPtr>, + + /// Slots for messages. + slots: [Slot; BLOCK_CAP], +} + +impl Block { + /// Creates an empty block. + fn new() -> Block { + // SAFETY: This is safe because: + // [1] `Block::next` (AtomicPtr) may be safely zero initialized. + // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. + // [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it + // holds a MaybeUninit. + // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. + unsafe { MaybeUninit::zeroed().assume_init() } + } + + /// Waits until the next pointer is set. + fn wait_next(&self) -> *mut Block { + let backoff = Backoff::new(); + loop { + let next = self.next.load(Ordering::Acquire); + if !next.is_null() { + return next; + } + backoff.snooze(); + } + } + + /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. + unsafe fn destroy(this: *mut Block, start: usize) { + // It is not necessary to set the `DESTROY` bit in the last slot because that slot has + // begun destruction of the block. + for i in start..BLOCK_CAP - 1 { + let slot = (*this).slots.get_unchecked(i); + + // Mark the `DESTROY` bit if a thread is still using the slot. + if slot.state.load(Ordering::Acquire) & READ == 0 + && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 + { + // If a thread is still using the slot, it will continue destruction of the block. + return; + } + } + + // No thread is using the block, now it is safe to destroy it. + drop(Box::from_raw(this)); + } +} + +/// A position in a channel. +#[derive(Debug)] +struct Position { + /// The index in the channel. + index: AtomicUsize, + + /// The block in the linked list. + block: AtomicPtr>, +} + +/// The token type for the list flavor. +#[derive(Debug)] +pub struct ListToken { + /// The block of slots. + block: *const u8, + + /// The offset into the block. + offset: usize, +} + +impl Default for ListToken { + #[inline] + fn default() -> Self { + ListToken { + block: ptr::null(), + offset: 0, + } + } +} + +/// Unbounded channel implemented as a linked list. +/// +/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are +/// represented as numbers of type `usize` and wrap on overflow. +/// +/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and +/// improve cache efficiency. +pub struct Channel { + /// The head of the channel. + head: CachePadded>, + + /// The tail of the channel. + tail: CachePadded>, + + /// Receivers waiting while the channel is empty and not disconnected. + receivers: SyncWaker, + + /// Indicates that dropping a `Channel` may drop messages of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Creates a new unbounded channel. + pub fn new() -> Self { + Channel { + head: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + tail: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + receivers: SyncWaker::new(), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver<'_, T> { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender<'_, T> { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut tail = self.tail.index.load(Ordering::Acquire); + let mut block = self.tail.block.load(Ordering::Acquire); + let mut next_block = None; + + loop { + // Check if the channel is disconnected. + if tail & MARK_BIT != 0 { + token.list.block = ptr::null(); + return true; + } + + // Calculate the offset of the index into the block. + let offset = (tail >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + + // If we're going to have to install the next block, allocate it in advance in order to + // make the wait for other threads as short as possible. + if offset + 1 == BLOCK_CAP && next_block.is_none() { + next_block = Some(Box::new(Block::::new())); + } + + // If this is the first message to be sent into the channel, we need to allocate the + // first block and install it. + if block.is_null() { + let new = Box::into_raw(Box::new(Block::::new())); + + if self + .tail + .block + .compare_and_swap(block, new, Ordering::Release) + == block + { + self.head.block.store(new, Ordering::Release); + block = new; + } else { + next_block = unsafe { Some(Box::from_raw(new)) }; + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + } + + let new_tail = tail + (1 << SHIFT); + + // Try advancing the tail forward. + match self.tail.index.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, install the next one. + if offset + 1 == BLOCK_CAP { + let next_block = Box::into_raw(next_block.unwrap()); + self.tail.block.store(next_block, Ordering::Release); + self.tail.index.fetch_add(1 << SHIFT, Ordering::Release); + (*block).next.store(next_block, Ordering::Release); + } + + token.list.block = block as *const u8; + token.list.offset = offset; + return true; + }, + Err(t) => { + tail = t; + block = self.tail.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Writes a message into the channel. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no slot, the channel is disconnected. + if token.list.block.is_null() { + return Err(msg); + } + + // Write the message into the slot. + let block = token.list.block as *mut Block; + let offset = token.list.offset; + let slot = (*block).slots.get_unchecked(offset); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.state.fetch_or(WRITE, Ordering::Release); + + // Wake a sleeping receiver. + self.receivers.notify(); + Ok(()) + } + + /// Attempts to reserve a slot for receiving a message. + fn start_recv(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut head = self.head.index.load(Ordering::Acquire); + let mut block = self.head.block.load(Ordering::Acquire); + + loop { + // Calculate the offset of the index into the block. + let offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + let mut new_head = head + (1 << SHIFT); + + if new_head & MARK_BIT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the channel is empty. + if head >> SHIFT == tail >> SHIFT { + // If the channel is disconnected... + if tail & MARK_BIT != 0 { + // ...then receive an error. + token.list.block = ptr::null(); + return true; + } else { + // Otherwise, the receive operation is not ready. + return false; + } + } + + // If head and tail are not in the same block, set `MARK_BIT` in head. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= MARK_BIT; + } + } + + // The block can be null here only if the first message is being sent into the channel. + // In that case, just wait until it gets initialized. + if block.is_null() { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + // Try moving the head index forward. + match self.head.index.compare_exchange_weak( + head, + new_head, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, move to the next one. + if offset + 1 == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= MARK_BIT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + token.list.block = block as *const u8; + token.list.offset = offset; + return true; + }, + Err(h) => { + head = h; + block = self.head.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Reads a message from the channel. + pub unsafe fn read(&self, token: &mut Token) -> Result { + if token.list.block.is_null() { + // The channel is disconnected. + return Err(()); + } + + // Read the message. + let block = token.list.block as *mut Block; + let offset = token.list.offset; + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let msg = slot.msg.get().read().assume_init(); + + // Destroy the block if we've reached the end, or if another thread wanted to destroy but + // couldn't because we were busy reading from the slot. + if offset + 1 == BLOCK_CAP { + Block::destroy(block, 0); + } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset + 1); + } + + Ok(msg) + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + self.send(msg, None).map_err(|err| match err { + SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg), + SendTimeoutError::Timeout(_) => unreachable!(), + }) + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, _deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + assert!(self.start_send(token)); + unsafe { + self.write(token, msg) + .map_err(SendTimeoutError::Disconnected) + } + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + + if self.start_recv(token) { + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + loop { + // Try receiving a message several times. + let backoff = Backoff::new(); + loop { + if self.start_recv(token) { + unsafe { + return self.read(token).map_err(|_| RecvTimeoutError::Disconnected); + } + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(RecvTimeoutError::Timeout); + } + } + + // Prepare for blocking until a sender wakes us up. + Context::with(|cx| { + let oper = Operation::hook(token); + self.receivers.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_empty() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.receivers.unregister(oper).unwrap(); + // If the channel was disconnected, we still have to check for remaining + // messages. + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + loop { + // Load the tail index, then load the head index. + let mut tail = self.tail.index.load(Ordering::SeqCst); + let mut head = self.head.index.load(Ordering::SeqCst); + + // If the tail index didn't change, we've got consistent indices to work with. + if self.tail.index.load(Ordering::SeqCst) == tail { + // Erase the lower bits. + tail &= !((1 << SHIFT) - 1); + head &= !((1 << SHIFT) - 1); + + // Fix up indices if they fall onto block ends. + if (tail >> SHIFT) & (LAP - 1) == LAP - 1 { + tail = tail.wrapping_add(1 << SHIFT); + } + if (head >> SHIFT) & (LAP - 1) == LAP - 1 { + head = head.wrapping_add(1 << SHIFT); + } + + // Rotate indices so that head falls into the first block. + let lap = (head >> SHIFT) / LAP; + tail = tail.wrapping_sub((lap * LAP) << SHIFT); + head = head.wrapping_sub((lap * LAP) << SHIFT); + + // Remove the lower bits. + tail >>= SHIFT; + head >>= SHIFT; + + // Return the difference minus the number of blocks between tail and head. + return tail - head - tail / LAP; + } + } + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + None + } + + /// Disconnects the channel and wakes up all blocked receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst); + + if tail & MARK_BIT == 0 { + self.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns `true` if the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0 + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + let head = self.head.index.load(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::SeqCst); + head >> SHIFT == tail >> SHIFT + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + false + } +} + +impl Drop for Channel { + fn drop(&mut self) { + let mut head = self.head.index.load(Ordering::Relaxed); + let mut tail = self.tail.index.load(Ordering::Relaxed); + let mut block = self.head.block.load(Ordering::Relaxed); + + // Erase the lower bits. + head &= !((1 << SHIFT) - 1); + tail &= !((1 << SHIFT) - 1); + + unsafe { + // Drop all messages between head and tail and deallocate the heap-allocated blocks. + while head != tail { + let offset = (head >> SHIFT) % LAP; + + if offset < BLOCK_CAP { + // Drop the message in the slot. + let slot = (*block).slots.get_unchecked(offset); + let p = &mut *slot.msg.get(); + p.as_mut_ptr().drop_in_place(); + } else { + // Deallocate the block and move to the next one. + let next = (*block).next.load(Ordering::Relaxed); + drop(Box::from_raw(block)); + block = next; + } + + head = head.wrapping_add(1 << SHIFT); + } + + // Deallocate the last remaining block. + if !block.is_null() { + drop(Box::from_raw(block)); + } + } + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T>(&'a Channel); + +impl SelectHandle for Receiver<'_, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.receivers.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_empty() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.receivers.unwatch(oper); + } +} + +impl SelectHandle for Sender<'_, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + fn unregister(&self, _oper: Operation) {} + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + true + } + + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + fn unwatch(&self, _oper: Operation) {} +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/mod.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/mod.rs new file mode 100644 index 0000000..299e78f --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/mod.rs @@ -0,0 +1,17 @@ +//! Channel flavors. +//! +//! There are six flavors: +//! +//! 1. `at` - Channel that delivers a message after a certain amount of time. +//! 2. `array` - Bounded channel based on a preallocated array. +//! 3. `list` - Unbounded channel implemented as a linked list. +//! 4. `never` - Channel that never delivers messages. +//! 5. `tick` - Channel that delivers messages periodically. +//! 6. `zero` - Zero-capacity channel. + +pub mod array; +pub mod at; +pub mod list; +pub mod never; +pub mod tick; +pub mod zero; diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/never.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/never.rs new file mode 100644 index 0000000..e49d214 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/never.rs @@ -0,0 +1,110 @@ +//! Channel that never delivers messages. +//! +//! Messages cannot be sent into this kind of channel. + +use std::marker::PhantomData; +use std::time::Instant; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, TryRecvError}; +use crate::select::{Operation, SelectHandle, Token}; +use crate::utils; + +/// This flavor doesn't need a token. +pub type NeverToken = (); + +/// Channel that never delivers messages. +pub struct Channel { + _marker: PhantomData, +} + +impl Channel { + /// Creates a channel that never delivers messages. + #[inline] + pub fn new() -> Self { + Channel { + _marker: PhantomData, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + Err(TryRecvError::Empty) + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + utils::sleep_until(deadline); + Err(RecvTimeoutError::Timeout) + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, _token: &mut Token) -> Result { + Err(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + true + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(0) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, _token: &mut Token) -> bool { + false + } + + #[inline] + fn deadline(&self) -> Option { + None + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + false + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/tick.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/tick.rs new file mode 100644 index 0000000..e8e7020 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/tick.rs @@ -0,0 +1,167 @@ +//! Channel that delivers messages periodically. +//! +//! Messages cannot be sent into this kind of channel; they are materialized on demand. + +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_utils::atomic::AtomicCell; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, TryRecvError}; +use crate::select::{Operation, SelectHandle, Token}; + +/// Result of a receive operation. +pub type TickToken = Option; + +/// Channel that delivers messages periodically. +pub struct Channel { + /// The instant at which the next message will be delivered. + delivery_time: AtomicCell, + + /// The time interval in which messages get delivered. + duration: Duration, +} + +impl Channel { + /// Creates a channel that delivers messages periodically. + #[inline] + pub fn new(dur: Duration) -> Self { + Channel { + delivery_time: AtomicCell::new(Instant::now() + dur), + duration: dur, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + loop { + let now = Instant::now(); + let delivery_time = self.delivery_time.load(); + + if now < delivery_time { + return Err(TryRecvError::Empty); + } + + if self + .delivery_time + .compare_exchange(delivery_time, now + self.duration) + .is_ok() + { + return Ok(delivery_time); + } + } + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + loop { + let delivery_time = self.delivery_time.load(); + let now = Instant::now(); + + if let Some(d) = deadline { + if d < delivery_time { + if now < d { + thread::sleep(d - now); + } + return Err(RecvTimeoutError::Timeout); + } + } + + if self + .delivery_time + .compare_exchange(delivery_time, delivery_time.max(now) + self.duration) + .is_ok() + { + if now < delivery_time { + thread::sleep(delivery_time - now); + } + return Ok(delivery_time); + } + } + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, token: &mut Token) -> Result { + token.tick.ok_or(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + Instant::now() < self.delivery_time.load() + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + if self.is_empty() { + 0 + } else { + 1 + } + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(1) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, token: &mut Token) -> bool { + match self.try_recv() { + Ok(msg) => { + token.tick = Some(msg); + true + } + Err(TryRecvError::Disconnected) => { + token.tick = None; + true + } + Err(TryRecvError::Empty) => false, + } + } + + #[inline] + fn deadline(&self) -> Option { + Some(self.delivery_time.load()) + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + !self.is_empty() + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/zero.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/zero.rs new file mode 100644 index 0000000..be647b5 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/flavors/zero.rs @@ -0,0 +1,466 @@ +//! Zero-capacity channel. +//! +//! This kind of channel is also known as *rendezvous* channel. + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Instant; + +use crossbeam_utils::Backoff; + +use crate::context::Context; +use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use crate::select::{Operation, SelectHandle, Selected, Token}; +use crate::utils::Spinlock; +use crate::waker::Waker; + +/// A pointer to a packet. +pub type ZeroToken = usize; + +/// A slot for passing one message from a sender to a receiver. +struct Packet { + /// Equals `true` if the packet is allocated on the stack. + on_stack: bool, + + /// Equals `true` once the packet is ready for reading or writing. + ready: AtomicBool, + + /// The message. + msg: UnsafeCell>, +} + +impl Packet { + /// Creates an empty packet on the stack. + fn empty_on_stack() -> Packet { + Packet { + on_stack: true, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(None), + } + } + + /// Creates an empty packet on the heap. + fn empty_on_heap() -> Box> { + Box::new(Packet { + on_stack: false, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(None), + }) + } + + /// Creates a packet on the stack, containing a message. + fn message_on_stack(msg: T) -> Packet { + Packet { + on_stack: true, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(Some(msg)), + } + } + + /// Waits until the packet becomes ready for reading or writing. + fn wait_ready(&self) { + let backoff = Backoff::new(); + while !self.ready.load(Ordering::Acquire) { + backoff.snooze(); + } + } +} + +/// Inner representation of a zero-capacity channel. +struct Inner { + /// Senders waiting to pair up with a receive operation. + senders: Waker, + + /// Receivers waiting to pair up with a send operation. + receivers: Waker, + + /// Equals `true` when the channel is disconnected. + is_disconnected: bool, +} + +/// Zero-capacity channel. +pub struct Channel { + /// Inner representation of the channel. + inner: Spinlock, + + /// Indicates that dropping a `Channel` may drop values of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Constructs a new zero-capacity channel. + pub fn new() -> Self { + Channel { + inner: Spinlock::new(Inner { + senders: Waker::new(), + receivers: Waker::new(), + is_disconnected: false, + }), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver<'_, T> { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender<'_, T> { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + true + } else if inner.is_disconnected { + token.zero = 0; + true + } else { + false + } + } + + /// Writes a message into the packet. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no packet, the channel is disconnected. + if token.zero == 0 { + return Err(msg); + } + + let packet = &*(token.zero as *const Packet); + packet.msg.get().write(Some(msg)); + packet.ready.store(true, Ordering::Release); + Ok(()) + } + + /// Attempts to pair up with a sender. + fn start_recv(&self, token: &mut Token) -> bool { + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + true + } else if inner.is_disconnected { + token.zero = 0; + true + } else { + false + } + } + + /// Reads a message from the packet. + pub unsafe fn read(&self, token: &mut Token) -> Result { + // If there is no packet, the channel is disconnected. + if token.zero == 0 { + return Err(()); + } + + let packet = &*(token.zero as *const Packet); + + if packet.on_stack { + // The message has been in the packet from the beginning, so there is no need to wait + // for it. However, after reading the message, we need to set `ready` to `true` in + // order to signal that the packet can be destroyed. + let msg = packet.msg.get().replace(None).unwrap(); + packet.ready.store(true, Ordering::Release); + Ok(msg) + } else { + // Wait until the message becomes available, then read it and destroy the + // heap-allocated packet. + packet.wait_ready(); + let msg = packet.msg.get().replace(None).unwrap(); + drop(Box::from_raw(packet as *const Packet as *mut Packet)); + Ok(msg) + } + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + self.write(token, msg).ok().unwrap(); + } + Ok(()) + } else if inner.is_disconnected { + Err(TrySendError::Disconnected(msg)) + } else { + Err(TrySendError::Full(msg)) + } + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + self.write(token, msg).ok().unwrap(); + } + return Ok(()); + } + + if inner.is_disconnected { + return Err(SendTimeoutError::Disconnected(msg)); + } + + Context::with(|cx| { + // Prepare for blocking until a receiver wakes us up. + let oper = Operation::hook(token); + let packet = Packet::::message_on_stack(msg); + inner + .senders + .register_with_packet(oper, &packet as *const Packet as usize, cx); + inner.receivers.notify(); + drop(inner); + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + self.inner.lock().senders.unregister(oper).unwrap(); + let msg = unsafe { packet.msg.get().replace(None).unwrap() }; + Err(SendTimeoutError::Timeout(msg)) + } + Selected::Disconnected => { + self.inner.lock().senders.unregister(oper).unwrap(); + let msg = unsafe { packet.msg.get().replace(None).unwrap() }; + Err(SendTimeoutError::Disconnected(msg)) + } + Selected::Operation(_) => { + // Wait until the message is read, then drop the packet. + packet.wait_ready(); + Ok(()) + } + } + }) + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else if inner.is_disconnected { + Err(TryRecvError::Disconnected) + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + return self.read(token).map_err(|_| RecvTimeoutError::Disconnected); + } + } + + if inner.is_disconnected { + return Err(RecvTimeoutError::Disconnected); + } + + Context::with(|cx| { + // Prepare for blocking until a sender wakes us up. + let oper = Operation::hook(token); + let packet = Packet::::empty_on_stack(); + inner + .receivers + .register_with_packet(oper, &packet as *const Packet as usize, cx); + inner.senders.notify(); + drop(inner); + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + self.inner.lock().receivers.unregister(oper).unwrap(); + Err(RecvTimeoutError::Timeout) + } + Selected::Disconnected => { + self.inner.lock().receivers.unregister(oper).unwrap(); + Err(RecvTimeoutError::Disconnected) + } + Selected::Operation(_) => { + // Wait until the message is provided, then read it. + packet.wait_ready(); + unsafe { Ok(packet.msg.get().replace(None).unwrap()) } + } + } + }) + } + + /// Disconnects the channel and wakes up all blocked senders and receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let mut inner = self.inner.lock(); + + if !inner.is_disconnected { + inner.is_disconnected = true; + inner.senders.disconnect(); + inner.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + Some(0) + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + true + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T>(&'a Channel); + +impl SelectHandle for Receiver<'_, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + let packet = Box::into_raw(Packet::::empty_on_heap()); + + let mut inner = self.0.inner.lock(); + inner + .receivers + .register_with_packet(oper, packet as usize, cx); + inner.senders.notify(); + inner.senders.can_select() || inner.is_disconnected + } + + fn unregister(&self, oper: Operation) { + if let Some(operation) = self.0.inner.lock().receivers.unregister(oper) { + unsafe { + drop(Box::from_raw(operation.packet as *mut Packet)); + } + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + token.zero = cx.wait_packet(); + true + } + + fn is_ready(&self) -> bool { + let inner = self.0.inner.lock(); + inner.senders.can_select() || inner.is_disconnected + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + let mut inner = self.0.inner.lock(); + inner.receivers.watch(oper, cx); + inner.senders.can_select() || inner.is_disconnected + } + + fn unwatch(&self, oper: Operation) { + let mut inner = self.0.inner.lock(); + inner.receivers.unwatch(oper); + } +} + +impl SelectHandle for Sender<'_, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + let packet = Box::into_raw(Packet::::empty_on_heap()); + + let mut inner = self.0.inner.lock(); + inner + .senders + .register_with_packet(oper, packet as usize, cx); + inner.receivers.notify(); + inner.receivers.can_select() || inner.is_disconnected + } + + fn unregister(&self, oper: Operation) { + if let Some(operation) = self.0.inner.lock().senders.unregister(oper) { + unsafe { + drop(Box::from_raw(operation.packet as *mut Packet)); + } + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + token.zero = cx.wait_packet(); + true + } + + fn is_ready(&self) -> bool { + let inner = self.0.inner.lock(); + inner.receivers.can_select() || inner.is_disconnected + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + let mut inner = self.0.inner.lock(); + inner.senders.watch(oper, cx); + inner.receivers.can_select() || inner.is_disconnected + } + + fn unwatch(&self, oper: Operation) { + let mut inner = self.0.inner.lock(); + inner.senders.unwatch(oper); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/lib.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/lib.rs new file mode 100644 index 0000000..e08ac08 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/lib.rs @@ -0,0 +1,368 @@ +//! Multi-producer multi-consumer channels for message passing. +//! +//! This crate is an alternative to [`std::sync::mpsc`] with more features and better performance. +//! +//! # Hello, world! +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! // Create a channel of unbounded capacity. +//! let (s, r) = unbounded(); +//! +//! // Send a message into the channel. +//! s.send("Hello, world!").unwrap(); +//! +//! // Receive the message from the channel. +//! assert_eq!(r.recv(), Ok("Hello, world!")); +//! ``` +//! +//! # Channel types +//! +//! Channels can be created using two functions: +//! +//! * [`bounded`] creates a channel of bounded capacity, i.e. there is a limit to how many messages +//! it can hold at a time. +//! +//! * [`unbounded`] creates a channel of unbounded capacity, i.e. it can hold any number of +//! messages at a time. +//! +//! Both functions return a [`Sender`] and a [`Receiver`], which represent the two opposite sides +//! of a channel. +//! +//! Creating a bounded channel: +//! +//! ``` +//! use crossbeam_channel::bounded; +//! +//! // Create a channel that can hold at most 5 messages at a time. +//! let (s, r) = bounded(5); +//! +//! // Can send only 5 messages without blocking. +//! for i in 0..5 { +//! s.send(i).unwrap(); +//! } +//! +//! // Another call to `send` would block because the channel is full. +//! // s.send(5).unwrap(); +//! ``` +//! +//! Creating an unbounded channel: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! // Create an unbounded channel. +//! let (s, r) = unbounded(); +//! +//! // Can send any number of messages into the channel without blocking. +//! for i in 0..1000 { +//! s.send(i).unwrap(); +//! } +//! ``` +//! +//! A special case is zero-capacity channel, which cannot hold any messages. Instead, send and +//! receive operations must appear at the same time in order to pair up and pass the message over: +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::bounded; +//! +//! // Create a zero-capacity channel. +//! let (s, r) = bounded(0); +//! +//! // Sending blocks until a receive operation appears on the other side. +//! thread::spawn(move || s.send("Hi!").unwrap()); +//! +//! // Receiving blocks until a send operation appears on the other side. +//! assert_eq!(r.recv(), Ok("Hi!")); +//! ``` +//! +//! # Sharing channels +//! +//! Senders and receivers can be cloned and sent to other threads: +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::bounded; +//! +//! let (s1, r1) = bounded(0); +//! let (s2, r2) = (s1.clone(), r1.clone()); +//! +//! // Spawn a thread that receives a message and then sends one. +//! thread::spawn(move || { +//! r2.recv().unwrap(); +//! s2.send(2).unwrap(); +//! }); +//! +//! // Send a message and then receive one. +//! s1.send(1).unwrap(); +//! r1.recv().unwrap(); +//! ``` +//! +//! Note that cloning only creates a new handle to the same sending or receiving side. It does not +//! create a separate stream of messages in any way: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! let (s1, r1) = unbounded(); +//! let (s2, r2) = (s1.clone(), r1.clone()); +//! let (s3, r3) = (s2.clone(), r2.clone()); +//! +//! s1.send(10).unwrap(); +//! s2.send(20).unwrap(); +//! s3.send(30).unwrap(); +//! +//! assert_eq!(r3.recv(), Ok(10)); +//! assert_eq!(r1.recv(), Ok(20)); +//! assert_eq!(r2.recv(), Ok(30)); +//! ``` +//! +//! It's also possible to share senders and receivers by reference: +//! +//! ``` +//! use crossbeam_channel::bounded; +//! use crossbeam_utils::thread::scope; +//! +//! let (s, r) = bounded(0); +//! +//! scope(|scope| { +//! // Spawn a thread that receives a message and then sends one. +//! scope.spawn(|_| { +//! r.recv().unwrap(); +//! s.send(2).unwrap(); +//! }); +//! +//! // Send a message and then receive one. +//! s.send(1).unwrap(); +//! r.recv().unwrap(); +//! }).unwrap(); +//! ``` +//! +//! # Disconnection +//! +//! When all senders or all receivers associated with a channel get dropped, the channel becomes +//! disconnected. No more messages can be sent, but any remaining messages can still be received. +//! Send and receive operations on a disconnected channel never block. +//! +//! ``` +//! use crossbeam_channel::{unbounded, RecvError}; +//! +//! let (s, r) = unbounded(); +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! +//! // The only sender is dropped, disconnecting the channel. +//! drop(s); +//! +//! // The remaining messages can be received. +//! assert_eq!(r.recv(), Ok(1)); +//! assert_eq!(r.recv(), Ok(2)); +//! assert_eq!(r.recv(), Ok(3)); +//! +//! // There are no more messages in the channel. +//! assert!(r.is_empty()); +//! +//! // Note that calling `r.recv()` does not block. +//! // Instead, `Err(RecvError)` is returned immediately. +//! assert_eq!(r.recv(), Err(RecvError)); +//! ``` +//! +//! # Blocking operations +//! +//! Send and receive operations come in three flavors: +//! +//! * Non-blocking (returns immediately with success or failure). +//! * Blocking (waits until the operation succeeds or the channel becomes disconnected). +//! * Blocking with a timeout (blocks only for a certain duration of time). +//! +//! A simple example showing the difference between non-blocking and blocking operations: +//! +//! ``` +//! use crossbeam_channel::{bounded, RecvError, TryRecvError}; +//! +//! let (s, r) = bounded(1); +//! +//! // Send a message into the channel. +//! s.send("foo").unwrap(); +//! +//! // This call would block because the channel is full. +//! // s.send("bar").unwrap(); +//! +//! // Receive the message. +//! assert_eq!(r.recv(), Ok("foo")); +//! +//! // This call would block because the channel is empty. +//! // r.recv(); +//! +//! // Try receiving a message without blocking. +//! assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +//! +//! // Disconnect the channel. +//! drop(s); +//! +//! // This call doesn't block because the channel is now disconnected. +//! assert_eq!(r.recv(), Err(RecvError)); +//! ``` +//! +//! # Iteration +//! +//! Receivers can be used as iterators. For example, method [`iter`] creates an iterator that +//! receives messages until the channel becomes empty and disconnected. Note that iteration may +//! block waiting for next message to arrive. +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::unbounded; +//! +//! let (s, r) = unbounded(); +//! +//! thread::spawn(move || { +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! drop(s); // Disconnect the channel. +//! }); +//! +//! // Collect all messages from the channel. +//! // Note that the call to `collect` blocks until the sender is dropped. +//! let v: Vec<_> = r.iter().collect(); +//! +//! assert_eq!(v, [1, 2, 3]); +//! ``` +//! +//! A non-blocking iterator can be created using [`try_iter`], which receives all available +//! messages without blocking: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! let (s, r) = unbounded(); +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! // No need to drop the sender. +//! +//! // Receive all messages currently in the channel. +//! let v: Vec<_> = r.try_iter().collect(); +//! +//! assert_eq!(v, [1, 2, 3]); +//! ``` +//! +//! # Selection +//! +//! The [`select!`] macro allows you to define a set of channel operations, wait until any one of +//! them becomes ready, and finally execute it. If multiple operations are ready at the same time, +//! a random one among them is selected. +//! +//! It is also possible to define a `default` case that gets executed if none of the operations are +//! ready, either right away or for a certain duration of time. +//! +//! An operation is considered to be ready if it doesn't have to block. Note that it is ready even +//! when it will simply return an error because the channel is disconnected. +//! +//! An example of receiving a message from two channels: +//! +//! ``` +//! use std::thread; +//! use std::time::Duration; +//! use crossbeam_channel::{select, unbounded}; +//! +//! let (s1, r1) = unbounded(); +//! let (s2, r2) = unbounded(); +//! +//! thread::spawn(move || s1.send(10).unwrap()); +//! thread::spawn(move || s2.send(20).unwrap()); +//! +//! // At most one of these two receive operations will be executed. +//! select! { +//! recv(r1) -> msg => assert_eq!(msg, Ok(10)), +//! recv(r2) -> msg => assert_eq!(msg, Ok(20)), +//! default(Duration::from_secs(1)) => println!("timed out"), +//! } +//! ``` +//! +//! If you need to select over a dynamically created list of channel operations, use [`Select`] +//! instead. The [`select!`] macro is just a convenience wrapper around [`Select`]. +//! +//! # Extra channels +//! +//! Three functions can create special kinds of channels, all of which return just a [`Receiver`] +//! handle: +//! +//! * [`after`] creates a channel that delivers a single message after a certain duration of time. +//! * [`tick`] creates a channel that delivers messages periodically. +//! * [`never`] creates a channel that never delivers messages. +//! +//! These channels are very efficient because messages get lazily generated on receive operations. +//! +//! An example that prints elapsed time every 50 milliseconds for the duration of 1 second: +//! +//! ``` +//! use std::time::{Duration, Instant}; +//! use crossbeam_channel::{after, select, tick}; +//! +//! let start = Instant::now(); +//! let ticker = tick(Duration::from_millis(50)); +//! let timeout = after(Duration::from_secs(1)); +//! +//! loop { +//! select! { +//! recv(ticker) -> _ => println!("elapsed: {:?}", start.elapsed()), +//! recv(timeout) -> _ => break, +//! } +//! } +//! ``` +//! +//! [`send`]: Sender::send +//! [`recv`]: Receiver::recv +//! [`iter`]: Receiver::iter +//! [`try_iter`]: Receiver::try_iter + +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms), + allow(dead_code, unused_assignments, unused_variables) + ) +))] +#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] +#![cfg_attr(not(feature = "std"), no_std)] +// matches! requires Rust 1.42 +#![allow(clippy::match_like_matches_macro)] + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "std")] { + mod channel; + mod context; + mod counter; + mod err; + mod flavors; + mod select; + mod select_macro; + mod utils; + mod waker; + + /// Crate internals used by the `select!` macro. + #[doc(hidden)] + pub mod internal { + pub use crate::select::SelectHandle; + pub use crate::select::{select, select_timeout, try_select}; + } + + pub use crate::channel::{after, at, never, tick}; + pub use crate::channel::{bounded, unbounded}; + pub use crate::channel::{IntoIter, Iter, TryIter}; + pub use crate::channel::{Receiver, Sender}; + + pub use crate::select::{Select, SelectedOperation}; + + pub use crate::err::{ReadyTimeoutError, SelectTimeoutError, TryReadyError, TrySelectError}; + pub use crate::err::{RecvError, RecvTimeoutError, TryRecvError}; + pub use crate::err::{SendError, SendTimeoutError, TrySendError}; + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/select.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/select.rs new file mode 100644 index 0000000..1488f80 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/select.rs @@ -0,0 +1,1251 @@ +//! Interface to the select mechanism. + +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::time::{Duration, Instant}; + +use crossbeam_utils::Backoff; + +use crate::channel::{self, Receiver, Sender}; +use crate::context::Context; +use crate::err::{ReadyTimeoutError, TryReadyError}; +use crate::err::{RecvError, SendError}; +use crate::err::{SelectTimeoutError, TrySelectError}; +use crate::flavors; +use crate::utils; + +/// Temporary data that gets initialized during select or a blocking operation, and is consumed by +/// `read` or `write`. +/// +/// Each field contains data associated with a specific channel flavor. +#[derive(Debug, Default)] +pub struct Token { + pub at: flavors::at::AtToken, + pub array: flavors::array::ArrayToken, + pub list: flavors::list::ListToken, + pub never: flavors::never::NeverToken, + pub tick: flavors::tick::TickToken, + pub zero: flavors::zero::ZeroToken, +} + +/// Identifier associated with an operation by a specific thread on a specific channel. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Operation(usize); + +impl Operation { + /// Creates an operation identifier from a mutable reference. + /// + /// This function essentially just turns the address of the reference into a number. The + /// reference should point to a variable that is specific to the thread and the operation, + /// and is alive for the entire duration of select or blocking operation. + #[inline] + pub fn hook(r: &mut T) -> Operation { + let val = r as *mut T as usize; + // Make sure that the pointer address doesn't equal the numerical representation of + // `Selected::{Waiting, Aborted, Disconnected}`. + assert!(val > 2); + Operation(val) + } +} + +/// Current state of a select or a blocking operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Selected { + /// Still waiting for an operation. + Waiting, + + /// The attempt to block the current thread has been aborted. + Aborted, + + /// An operation became ready because a channel is disconnected. + Disconnected, + + /// An operation became ready because a message can be sent or received. + Operation(Operation), +} + +impl From for Selected { + #[inline] + fn from(val: usize) -> Selected { + match val { + 0 => Selected::Waiting, + 1 => Selected::Aborted, + 2 => Selected::Disconnected, + oper => Selected::Operation(Operation(oper)), + } + } +} + +impl Into for Selected { + #[inline] + fn into(self) -> usize { + match self { + Selected::Waiting => 0, + Selected::Aborted => 1, + Selected::Disconnected => 2, + Selected::Operation(Operation(val)) => val, + } + } +} + +/// A receiver or a sender that can participate in select. +/// +/// This is a handle that assists select in executing an operation, registration, deciding on the +/// appropriate deadline for blocking, etc. +pub trait SelectHandle { + /// Attempts to select an operation and returns `true` on success. + fn try_select(&self, token: &mut Token) -> bool; + + /// Returns a deadline for an operation, if there is one. + fn deadline(&self) -> Option; + + /// Registers an operation for execution and returns `true` if it is now ready. + fn register(&self, oper: Operation, cx: &Context) -> bool; + + /// Unregisters an operation for execution. + fn unregister(&self, oper: Operation); + + /// Attempts to select an operation the thread got woken up for and returns `true` on success. + fn accept(&self, token: &mut Token, cx: &Context) -> bool; + + /// Returns `true` if an operation can be executed without blocking. + fn is_ready(&self) -> bool; + + /// Registers an operation for readiness notification and returns `true` if it is now ready. + fn watch(&self, oper: Operation, cx: &Context) -> bool; + + /// Unregisters an operation for readiness notification. + fn unwatch(&self, oper: Operation); +} + +impl SelectHandle for &T { + fn try_select(&self, token: &mut Token) -> bool { + (**self).try_select(token) + } + + fn deadline(&self) -> Option { + (**self).deadline() + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + (**self).register(oper, cx) + } + + fn unregister(&self, oper: Operation) { + (**self).unregister(oper); + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + (**self).accept(token, cx) + } + + fn is_ready(&self) -> bool { + (**self).is_ready() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + (**self).watch(oper, cx) + } + + fn unwatch(&self, oper: Operation) { + (**self).unwatch(oper) + } +} + +/// Determines when a select operation should time out. +#[derive(Clone, Copy, Eq, PartialEq)] +enum Timeout { + /// No blocking. + Now, + + /// Block forever. + Never, + + /// Time out after the time instant. + At(Instant), +} + +/// Runs until one of the operations is selected, potentially blocking the current thread. +/// +/// Successful receive operations will have to be followed up by `channel::read()` and successful +/// send operations by `channel::write()`. +fn run_select( + handles: &mut [(&dyn SelectHandle, usize, *const u8)], + timeout: Timeout, +) -> Option<(Token, usize, *const u8)> { + if handles.is_empty() { + // Wait until the timeout and return. + match timeout { + Timeout::Now => return None, + Timeout::Never => { + utils::sleep_until(None); + unreachable!(); + } + Timeout::At(when) => { + utils::sleep_until(Some(when)); + return None; + } + } + } + + // Shuffle the operations for fairness. + utils::shuffle(handles); + + // Create a token, which serves as a temporary variable that gets initialized in this function + // and is later used by a call to `channel::read()` or `channel::write()` that completes the + // selected operation. + let mut token = Token::default(); + + // Try selecting one of the operations without blocking. + for &(handle, i, ptr) in handles.iter() { + if handle.try_select(&mut token) { + return Some((token, i, ptr)); + } + } + + loop { + // Prepare for blocking. + let res = Context::with(|cx| { + let mut sel = Selected::Waiting; + let mut registered_count = 0; + let mut index_ready = None; + + if let Timeout::Now = timeout { + cx.try_select(Selected::Aborted).unwrap(); + } + + // Register all operations. + for (handle, i, _) in handles.iter_mut() { + registered_count += 1; + + // If registration returns `false`, that means the operation has just become ready. + if handle.register(Operation::hook::<&dyn SelectHandle>(handle), cx) { + // Try aborting select. + sel = match cx.try_select(Selected::Aborted) { + Ok(()) => { + index_ready = Some(*i); + Selected::Aborted + } + Err(s) => s, + }; + break; + } + + // If another thread has already selected one of the operations, stop registration. + sel = cx.selected(); + if sel != Selected::Waiting { + break; + } + } + + if sel == Selected::Waiting { + // Check with each operation for how long we're allowed to block, and compute the + // earliest deadline. + let mut deadline: Option = match timeout { + Timeout::Now => return None, + Timeout::Never => None, + Timeout::At(when) => Some(when), + }; + for &(handle, _, _) in handles.iter() { + if let Some(x) = handle.deadline() { + deadline = deadline.map(|y| x.min(y)).or(Some(x)); + } + } + + // Block the current thread. + sel = cx.wait_until(deadline); + } + + // Unregister all registered operations. + for (handle, _, _) in handles.iter_mut().take(registered_count) { + handle.unregister(Operation::hook::<&dyn SelectHandle>(handle)); + } + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + // If an operation became ready during registration, try selecting it. + if let Some(index_ready) = index_ready { + for &(handle, i, ptr) in handles.iter() { + if i == index_ready && handle.try_select(&mut token) { + return Some((i, ptr)); + } + } + } + } + Selected::Disconnected => {} + Selected::Operation(_) => { + // Find the selected operation. + for (handle, i, ptr) in handles.iter_mut() { + // Is this the selected operation? + if sel == Selected::Operation(Operation::hook::<&dyn SelectHandle>(handle)) + { + // Try selecting this operation. + if handle.accept(&mut token, cx) { + return Some((*i, *ptr)); + } + } + } + } + } + + None + }); + + // Return if an operation was selected. + if let Some((i, ptr)) = res { + return Some((token, i, ptr)); + } + + // Try selecting one of the operations without blocking. + for &(handle, i, ptr) in handles.iter() { + if handle.try_select(&mut token) { + return Some((token, i, ptr)); + } + } + + match timeout { + Timeout::Now => return None, + Timeout::Never => {} + Timeout::At(when) => { + if Instant::now() >= when { + return None; + } + } + } + } +} + +/// Runs until one of the operations becomes ready, potentially blocking the current thread. +fn run_ready( + handles: &mut [(&dyn SelectHandle, usize, *const u8)], + timeout: Timeout, +) -> Option { + if handles.is_empty() { + // Wait until the timeout and return. + match timeout { + Timeout::Now => return None, + Timeout::Never => { + utils::sleep_until(None); + unreachable!(); + } + Timeout::At(when) => { + utils::sleep_until(Some(when)); + return None; + } + } + } + + // Shuffle the operations for fairness. + utils::shuffle(handles); + + loop { + let backoff = Backoff::new(); + loop { + // Check operations for readiness. + for &(handle, i, _) in handles.iter() { + if handle.is_ready() { + return Some(i); + } + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + // Check for timeout. + match timeout { + Timeout::Now => return None, + Timeout::Never => {} + Timeout::At(when) => { + if Instant::now() >= when { + return None; + } + } + } + + // Prepare for blocking. + let res = Context::with(|cx| { + let mut sel = Selected::Waiting; + let mut registered_count = 0; + + // Begin watching all operations. + for (handle, _, _) in handles.iter_mut() { + registered_count += 1; + let oper = Operation::hook::<&dyn SelectHandle>(handle); + + // If registration returns `false`, that means the operation has just become ready. + if handle.watch(oper, cx) { + sel = match cx.try_select(Selected::Operation(oper)) { + Ok(()) => Selected::Operation(oper), + Err(s) => s, + }; + break; + } + + // If another thread has already chosen one of the operations, stop registration. + sel = cx.selected(); + if sel != Selected::Waiting { + break; + } + } + + if sel == Selected::Waiting { + // Check with each operation for how long we're allowed to block, and compute the + // earliest deadline. + let mut deadline: Option = match timeout { + Timeout::Now => unreachable!(), + Timeout::Never => None, + Timeout::At(when) => Some(when), + }; + for &(handle, _, _) in handles.iter() { + if let Some(x) = handle.deadline() { + deadline = deadline.map(|y| x.min(y)).or(Some(x)); + } + } + + // Block the current thread. + sel = cx.wait_until(deadline); + } + + // Unwatch all operations. + for (handle, _, _) in handles.iter_mut().take(registered_count) { + handle.unwatch(Operation::hook::<&dyn SelectHandle>(handle)); + } + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => {} + Selected::Disconnected => {} + Selected::Operation(_) => { + for (handle, i, _) in handles.iter_mut() { + let oper = Operation::hook::<&dyn SelectHandle>(handle); + if sel == Selected::Operation(oper) { + return Some(*i); + } + } + } + } + + None + }); + + // Return if an operation became ready. + if res.is_some() { + return res; + } + } +} + +/// Attempts to select one of the operations without blocking. +#[inline] +pub fn try_select<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], +) -> Result, TrySelectError> { + match run_select(handles, Timeout::Now) { + None => Err(TrySelectError), + Some((token, index, ptr)) => Ok(SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + }), + } +} + +/// Blocks until one of the operations becomes ready and selects it. +#[inline] +pub fn select<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], +) -> SelectedOperation<'a> { + if handles.is_empty() { + panic!("no operations have been added to `Select`"); + } + + let (token, index, ptr) = run_select(handles, Timeout::Never).unwrap(); + SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + } +} + +/// Blocks for a limited time until one of the operations becomes ready and selects it. +#[inline] +pub fn select_timeout<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], + timeout: Duration, +) -> Result, SelectTimeoutError> { + select_deadline(handles, Instant::now() + timeout) +} + +/// Blocks until a given deadline, or until one of the operations becomes ready and selects it. +#[inline] +pub fn select_deadline<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], + deadline: Instant, +) -> Result, SelectTimeoutError> { + match run_select(handles, Timeout::At(deadline)) { + None => Err(SelectTimeoutError), + Some((token, index, ptr)) => Ok(SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + }), + } +} + +/// Selects from a set of channel operations. +/// +/// `Select` allows you to define a set of channel operations, wait until any one of them becomes +/// ready, and finally execute it. If multiple operations are ready at the same time, a random one +/// among them is selected. +/// +/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even +/// when it will simply return an error because the channel is disconnected. +/// +/// The [`select!`] macro is a convenience wrapper around `Select`. However, it cannot select over a +/// dynamically created list of channel operations. +/// +/// Once a list of operations has been built with `Select`, there are two different ways of +/// proceeding: +/// +/// * Select an operation with [`try_select`], [`select`], or [`select_timeout`]. If successful, +/// the returned selected operation has already begun and **must** be completed. If we don't +/// complete it, a panic will occur. +/// +/// * Wait for an operation to become ready with [`try_ready`], [`ready`], or [`ready_timeout`]. If +/// successful, we may attempt to execute the operation, but are not obliged to. In fact, it's +/// possible for another thread to make the operation not ready just before we try executing it, +/// so it's wise to use a retry loop. However, note that these methods might return with success +/// spuriously, so it's a good idea to always double check if the operation is really ready. +/// +/// # Examples +/// +/// Use [`select`] to receive a message from a list of receivers: +/// +/// ``` +/// use crossbeam_channel::{Receiver, RecvError, Select}; +/// +/// fn recv_multiple(rs: &[Receiver]) -> Result { +/// // Build a list of operations. +/// let mut sel = Select::new(); +/// for r in rs { +/// sel.recv(r); +/// } +/// +/// // Complete the selected operation. +/// let oper = sel.select(); +/// let index = oper.index(); +/// oper.recv(&rs[index]) +/// } +/// ``` +/// +/// Use [`ready`] to receive a message from a list of receivers: +/// +/// ``` +/// use crossbeam_channel::{Receiver, RecvError, Select}; +/// +/// fn recv_multiple(rs: &[Receiver]) -> Result { +/// // Build a list of operations. +/// let mut sel = Select::new(); +/// for r in rs { +/// sel.recv(r); +/// } +/// +/// loop { +/// // Wait until a receive operation becomes ready and try executing it. +/// let index = sel.ready(); +/// let res = rs[index].try_recv(); +/// +/// // If the operation turns out not to be ready, retry. +/// if let Err(e) = res { +/// if e.is_empty() { +/// continue; +/// } +/// } +/// +/// // Success! +/// return res.map_err(|_| RecvError); +/// } +/// } +/// ``` +/// +/// [`try_select`]: Select::try_select +/// [`select`]: Select::select +/// [`select_timeout`]: Select::select_timeout +/// [`try_ready`]: Select::try_ready +/// [`ready`]: Select::ready +/// [`ready_timeout`]: Select::ready_timeout +pub struct Select<'a> { + /// A list of senders and receivers participating in selection. + handles: Vec<(&'a dyn SelectHandle, usize, *const u8)>, + + /// The next index to assign to an operation. + next_index: usize, +} + +unsafe impl Send for Select<'_> {} +unsafe impl Sync for Select<'_> {} + +impl<'a> Select<'a> { + /// Creates an empty list of channel operations for selection. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::Select; + /// + /// let mut sel = Select::new(); + /// + /// // The list of operations is empty, which means no operation can be selected. + /// assert!(sel.try_select().is_err()); + /// ``` + pub fn new() -> Select<'a> { + Select { + handles: Vec::with_capacity(4), + next_index: 0, + } + } + + /// Adds a send operation. + /// + /// Returns the index of the added operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s, r) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let index = sel.send(&s); + /// ``` + pub fn send(&mut self, s: &'a Sender) -> usize { + let i = self.next_index; + let ptr = s as *const Sender<_> as *const u8; + self.handles.push((s, i, ptr)); + self.next_index += 1; + i + } + + /// Adds a receive operation. + /// + /// Returns the index of the added operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s, r) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let index = sel.recv(&r); + /// ``` + pub fn recv(&mut self, r: &'a Receiver) -> usize { + let i = self.next_index; + let ptr = r as *const Receiver<_> as *const u8; + self.handles.push((r, i, ptr)); + self.next_index += 1; + i + } + + /// Removes a previously added operation. + /// + /// This is useful when an operation is selected because the channel got disconnected and we + /// want to try again to select a different operation instead. + /// + /// If new operations are added after removing some, the indices of removed operations will not + /// be reused. + /// + /// # Panics + /// + /// An attempt to remove a non-existing or already removed operation will panic. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded::(); + /// let (_, r2) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be executed. + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper2); + /// assert!(oper.recv(&r2).is_err()); + /// sel.remove(oper2); + /// + /// s1.send(10).unwrap(); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.recv(&r1), Ok(10)); + /// ``` + pub fn remove(&mut self, index: usize) { + assert!( + index < self.next_index, + "index out of bounds; {} >= {}", + index, + self.next_index, + ); + + let i = self + .handles + .iter() + .enumerate() + .find(|(_, (_, i, _))| *i == index) + .expect("no operation with this index") + .0; + + self.handles.swap_remove(i); + } + + /// Attempts to select one of the operations without blocking. + /// + /// If an operation is ready, it is selected and returned. If multiple operations are ready at + /// the same time, a random one among them is selected. If none of the operations are ready, an + /// error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// s1.send(10).unwrap(); + /// s2.send(20).unwrap(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be executed. + /// let oper = sel.try_select(); + /// match oper { + /// Err(_) => panic!("both operations should be ready"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn try_select(&mut self) -> Result, TrySelectError> { + try_select(&mut self.handles) + } + + /// Blocks until one of the operations becomes ready and selects it. + /// + /// Once an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// # Panics + /// + /// Panics if no operations have been added to `Select`. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select(); + /// match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// ``` + pub fn select(&mut self) -> SelectedOperation<'a> { + select(&mut self.handles) + } + + /// Blocks for a limited time until one of the operations becomes ready and selects it. + /// + /// If an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. If none of the operations + /// become ready for the specified duration, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select_timeout(Duration::from_millis(500)); + /// match oper { + /// Err(_) => panic!("should not have timed out"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn select_timeout( + &mut self, + timeout: Duration, + ) -> Result, SelectTimeoutError> { + select_timeout(&mut self.handles, timeout) + } + + /// Blocks until a given deadline, or until one of the operations becomes ready and selects it. + /// + /// If an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. If none of the operations + /// become ready before the given deadline, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::{Instant, Duration}; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// let deadline = Instant::now() + Duration::from_millis(500); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select_deadline(deadline); + /// match oper { + /// Err(_) => panic!("should not have timed out"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn select_deadline( + &mut self, + deadline: Instant, + ) -> Result, SelectTimeoutError> { + select_deadline(&mut self.handles, deadline) + } + + /// Attempts to find a ready operation without blocking. + /// + /// If an operation is ready, its index is returned. If multiple operations are ready at the + /// same time, a random one among them is chosen. If none of the operations are ready, an error + /// is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to always + /// double check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// s1.send(10).unwrap(); + /// s2.send(20).unwrap(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be chosen. + /// match sel.try_ready() { + /// Err(_) => panic!("both operations should be ready"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn try_ready(&mut self) -> Result { + match run_ready(&mut self.handles, Timeout::Now) { + None => Err(TryReadyError), + Some(index) => Ok(index), + } + } + + /// Blocks until one of the operations becomes ready. + /// + /// Once an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to always + /// double check if the operation is really ready. + /// + /// # Panics + /// + /// Panics if no operations have been added to `Select`. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready() { + /// i if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// i if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// _ => unreachable!(), + /// } + /// ``` + pub fn ready(&mut self) -> usize { + if self.handles.is_empty() { + panic!("no operations have been added to `Select`"); + } + + run_ready(&mut self.handles, Timeout::Never).unwrap() + } + + /// Blocks for a limited time until one of the operations becomes ready. + /// + /// If an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. If none of the operations become ready + /// for the specified duration, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to double + /// check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready_timeout(Duration::from_millis(500)) { + /// Err(_) => panic!("should not have timed out"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn ready_timeout(&mut self, timeout: Duration) -> Result { + self.ready_deadline(Instant::now() + timeout) + } + + /// Blocks until a given deadline, or until one of the operations becomes ready. + /// + /// If an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. If none of the operations become ready + /// before the deadline, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to double + /// check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let deadline = Instant::now() + Duration::from_millis(500); + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready_deadline(deadline) { + /// Err(_) => panic!("should not have timed out"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn ready_deadline(&mut self, deadline: Instant) -> Result { + match run_ready(&mut self.handles, Timeout::At(deadline)) { + None => Err(ReadyTimeoutError), + Some(index) => Ok(index), + } + } +} + +impl<'a> Clone for Select<'a> { + fn clone(&self) -> Select<'a> { + Select { + handles: self.handles.clone(), + next_index: self.next_index, + } + } +} + +impl<'a> Default for Select<'a> { + fn default() -> Select<'a> { + Select::new() + } +} + +impl fmt::Debug for Select<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Select { .. }") + } +} + +/// A selected operation that needs to be completed. +/// +/// To complete the operation, call [`send`] or [`recv`]. +/// +/// # Panics +/// +/// Forgetting to complete the operation is an error and might lead to deadlocks. If a +/// `SelectedOperation` is dropped without completion, a panic occurs. +/// +/// [`send`]: SelectedOperation::send +/// [`recv`]: SelectedOperation::recv +#[must_use] +pub struct SelectedOperation<'a> { + /// Token needed to complete the operation. + token: Token, + + /// The index of the selected operation. + index: usize, + + /// The address of the selected `Sender` or `Receiver`. + ptr: *const u8, + + /// Indicates that `Sender`s and `Receiver`s are borrowed. + _marker: PhantomData<&'a ()>, +} + +impl SelectedOperation<'_> { + /// Returns the index of the selected operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select}; + /// + /// let (s1, r1) = bounded::<()>(0); + /// let (s2, r2) = bounded::<()>(0); + /// let (s3, r3) = bounded::<()>(1); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.send(&s1); + /// let oper2 = sel.recv(&r2); + /// let oper3 = sel.send(&s3); + /// + /// // Only the last operation is ready. + /// let oper = sel.select(); + /// assert_eq!(oper.index(), 2); + /// assert_eq!(oper.index(), oper3); + /// + /// // Complete the operation. + /// oper.send(&s3, ()).unwrap(); + /// ``` + pub fn index(&self) -> usize { + self.index + } + + /// Completes the send operation. + /// + /// The passed [`Sender`] reference must be the same one that was used in [`Select::send`] + /// when the operation was added. + /// + /// # Panics + /// + /// Panics if an incorrect [`Sender`] reference is passed. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select, SendError}; + /// + /// let (s, r) = bounded::(0); + /// drop(r); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.send(&s); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.send(&s, 10), Err(SendError(10))); + /// ``` + pub fn send(mut self, s: &Sender, msg: T) -> Result<(), SendError> { + assert!( + s as *const Sender as *const u8 == self.ptr, + "passed a sender that wasn't selected", + ); + let res = unsafe { channel::write(s, &mut self.token, msg) }; + mem::forget(self); + res.map_err(SendError) + } + + /// Completes the receive operation. + /// + /// The passed [`Receiver`] reference must be the same one that was used in [`Select::recv`] + /// when the operation was added. + /// + /// # Panics + /// + /// Panics if an incorrect [`Receiver`] reference is passed. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select, RecvError}; + /// + /// let (s, r) = bounded::(0); + /// drop(s); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.recv(&r), Err(RecvError)); + /// ``` + pub fn recv(mut self, r: &Receiver) -> Result { + assert!( + r as *const Receiver as *const u8 == self.ptr, + "passed a receiver that wasn't selected", + ); + let res = unsafe { channel::read(r, &mut self.token) }; + mem::forget(self); + res.map_err(|_| RecvError) + } +} + +impl fmt::Debug for SelectedOperation<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("SelectedOperation { .. }") + } +} + +impl Drop for SelectedOperation<'_> { + fn drop(&mut self) { + panic!("dropped `SelectedOperation` without completing the operation"); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/select_macro.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/select_macro.rs new file mode 100644 index 0000000..f8b247e --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/select_macro.rs @@ -0,0 +1,1166 @@ +//! The `select!` macro. + +/// A helper macro for `select!` to hide the long list of macro patterns from the documentation. +/// +/// The macro consists of two stages: +/// 1. Parsing +/// 2. Code generation +/// +/// The parsing stage consists of these subparts: +/// 1. `@list`: Turns a list of tokens into a list of cases. +/// 2. `@list_errorN`: Diagnoses the syntax error. +/// 3. `@case`: Parses a single case and verifies its argument list. +/// +/// The codegen stage consists of these subparts: +/// 1. `@init`: Attempts to optimize `select!` away and initializes the list of handles. +/// 1. `@count`: Counts the listed cases. +/// 3. `@add`: Adds send/receive operations to the list of handles and starts selection. +/// 4. `@complete`: Completes the selected send/receive operation. +/// +/// If the parsing stage encounters a syntax error or the codegen stage ends up with too many +/// cases to process, the macro fails with a compile-time error. +#[doc(hidden)] +#[macro_export] +macro_rules! crossbeam_channel_internal { + // The list is empty. Now check the arguments of each processed case. + (@list + () + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($head)*) + () + () + ) + }; + // If necessary, insert an empty argument list after `default`. + (@list + (default => $($tail:tt)*) + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!( + @list + (default() => $($tail)*) + ($($head)*) + ) + }; + // But print an error if `default` is followed by a `->`. + (@list + (default -> $($tail:tt)*) + ($($head:tt)*) + ) => { + compile_error!( + "expected `=>` after `default` case, found `->`" + ) + }; + // Print an error if there's an `->` after the argument list in the default case. + (@list + (default $args:tt -> $($tail:tt)*) + ($($head:tt)*) + ) => { + compile_error!( + "expected `=>` after `default` case, found `->`" + ) + }; + // Print an error if there is a missing result in a recv case. + (@list + (recv($($args:tt)*) => $($tail:tt)*) + ($($head:tt)*) + ) => { + compile_error!( + "expected `->` after `recv` case, found `=>`" + ) + }; + // Print an error if there is a missing result in a send case. + (@list + (send($($args:tt)*) => $($tail:tt)*) + ($($head:tt)*) + ) => { + compile_error!( + "expected `->` after `send` operation, found `=>`" + ) + }; + // Make sure the arrow and the result are not repeated. + (@list + ($case:ident $args:tt -> $res:tt -> $($tail:tt)*) + ($($head:tt)*) + ) => { + compile_error!("expected `=>`, found `->`") + }; + // Print an error if there is a semicolon after the block. + (@list + ($case:ident $args:tt $(-> $res:pat)* => $body:block; $($tail:tt)*) + ($($head:tt)*) + ) => { + compile_error!( + "did you mean to put a comma instead of the semicolon after `}`?" + ) + }; + // The first case is separated by a comma. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr, $($tail:tt)*) + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!( + @list + ($($tail)*) + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Don't require a comma after the case if it has a proper block. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:block $($tail:tt)*) + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!( + @list + ($($tail)*) + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Only one case remains. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr) + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!( + @list + () + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Accept a trailing comma at the end of the list. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr,) + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!( + @list + () + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Diagnose and print an error. + (@list + ($($tail:tt)*) + ($($head:tt)*) + ) => { + $crate::crossbeam_channel_internal!(@list_error1 $($tail)*) + }; + // Stage 1: check the case type. + (@list_error1 recv $($tail:tt)*) => { + $crate::crossbeam_channel_internal!(@list_error2 recv $($tail)*) + }; + (@list_error1 send $($tail:tt)*) => { + $crate::crossbeam_channel_internal!(@list_error2 send $($tail)*) + }; + (@list_error1 default $($tail:tt)*) => { + $crate::crossbeam_channel_internal!(@list_error2 default $($tail)*) + }; + (@list_error1 $t:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected one of `recv`, `send`, or `default`, found `", + stringify!($t), + "`", + ) + ) + }; + (@list_error1 $($tail:tt)*) => { + $crate::crossbeam_channel_internal!(@list_error2 $($tail)*); + }; + // Stage 2: check the argument list. + (@list_error2 $case:ident) => { + compile_error!( + concat!( + "missing argument list after `", + stringify!($case), + "`", + ) + ) + }; + (@list_error2 $case:ident => $($tail:tt)*) => { + compile_error!( + concat!( + "missing argument list after `", + stringify!($case), + "`", + ) + ) + }; + (@list_error2 $($tail:tt)*) => { + $crate::crossbeam_channel_internal!(@list_error3 $($tail)*) + }; + // Stage 3: check the `=>` and what comes after it. + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)*) => { + compile_error!( + concat!( + "missing `=>` after `", + stringify!($case), + "` case", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* =>) => { + compile_error!( + "expected expression after `=>`" + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:expr; $($tail:tt)*) => { + compile_error!( + concat!( + "did you mean to put a comma instead of the semicolon after `", + stringify!($body), + "`?", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => recv($($a:tt)*) $($tail:tt)*) => { + compile_error!( + "expected an expression after `=>`" + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => send($($a:tt)*) $($tail:tt)*) => { + compile_error!( + "expected an expression after `=>`" + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => default($($a:tt)*) $($tail:tt)*) => { + compile_error!( + "expected an expression after `=>`" + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident($($a:tt)*) $($tail:tt)*) => { + compile_error!( + concat!( + "did you mean to put a comma after `", + stringify!($f), + "(", + stringify!($($a)*), + ")`?", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!($($a:tt)*) $($tail:tt)*) => { + compile_error!( + concat!( + "did you mean to put a comma after `", + stringify!($f), + "!(", + stringify!($($a)*), + ")`?", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident![$($a:tt)*] $($tail:tt)*) => { + compile_error!( + concat!( + "did you mean to put a comma after `", + stringify!($f), + "![", + stringify!($($a)*), + "]`?", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!{$($a:tt)*} $($tail:tt)*) => { + compile_error!( + concat!( + "did you mean to put a comma after `", + stringify!($f), + "!{", + stringify!($($a)*), + "}`?", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:tt $($tail:tt)*) => { + compile_error!( + concat!( + "did you mean to put a comma after `", + stringify!($body), + "`?", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) -> => $($tail:tt)*) => { + compile_error!("missing pattern after `->`") + }; + (@list_error3 $case:ident($($args:tt)*) $t:tt $(-> $r:pat)* => $($tail:tt)*) => { + compile_error!( + concat!( + "expected `->`, found `", + stringify!($t), + "`", + ) + ) + }; + (@list_error3 $case:ident($($args:tt)*) -> $t:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected a pattern, found `", + stringify!($t), + "`", + ) + ) + }; + (@list_error3 recv($($args:tt)*) $t:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected `->`, found `", + stringify!($t), + "`", + ) + ) + }; + (@list_error3 send($($args:tt)*) $t:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected `->`, found `", + stringify!($t), + "`", + ) + ) + }; + (@list_error3 recv $args:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected an argument list after `recv`, found `", + stringify!($args), + "`", + ) + ) + }; + (@list_error3 send $args:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected an argument list after `send`, found `", + stringify!($args), + "`", + ) + ) + }; + (@list_error3 default $args:tt $($tail:tt)*) => { + compile_error!( + concat!( + "expected an argument list or `=>` after `default`, found `", + stringify!($args), + "`", + ) + ) + }; + (@list_error3 $($tail:tt)*) => { + $crate::crossbeam_channel_internal!(@list_error4 $($tail)*) + }; + // Stage 4: fail with a generic error message. + (@list_error4 $($tail:tt)*) => { + compile_error!("invalid syntax") + }; + + // Success! All cases were parsed. + (@case + () + $cases:tt + $default:tt + ) => { + $crate::crossbeam_channel_internal!( + @init + $cases + $default + ) + }; + + // Check the format of a recv case. + (@case + (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* recv($r) -> $res => $body,) + $default + ) + }; + // Allow trailing comma... + (@case + (recv($r:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* recv($r) -> $res => $body,) + $default + ) + }; + // Print an error if the argument list is invalid. + (@case + (recv($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + compile_error!( + concat!( + "invalid argument list in `recv(", + stringify!($($args)*), + ")`", + ) + ) + }; + // Print an error if there is no argument list. + (@case + (recv $t:tt $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + compile_error!( + concat!( + "expected an argument list after `recv`, found `", + stringify!($t), + "`", + ) + ) + }; + + // Check the format of a send case. + (@case + (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* send($s, $m) -> $res => $body,) + $default + ) + }; + // Allow trailing comma... + (@case + (send($s:expr, $m:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* send($s, $m) -> $res => $body,) + $default + ) + }; + // Print an error if the argument list is invalid. + (@case + (send($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + compile_error!( + concat!( + "invalid argument list in `send(", + stringify!($($args)*), + ")`", + ) + ) + }; + // Print an error if there is no argument list. + (@case + (send $t:tt $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + compile_error!( + concat!( + "expected an argument list after `send`, found `", + stringify!($t), + "`", + ) + ) + }; + + // Check the format of a default case. + (@case + (default() => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default() => $body,) + ) + }; + // Check the format of a default case with timeout. + (@case + (default($timeout:expr) => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default($timeout) => $body,) + ) + }; + // Allow trailing comma... + (@case + (default($timeout:expr,) => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + $crate::crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default($timeout) => $body,) + ) + }; + // Check for duplicate default cases... + (@case + (default $($tail:tt)*) + $cases:tt + ($($def:tt)+) + ) => { + compile_error!( + "there can be only one `default` case in a `select!` block" + ) + }; + // Print an error if the argument list is invalid. + (@case + (default($($args:tt)*) => $body:tt, $($tail:tt)*) + $cases:tt + $default:tt + ) => { + compile_error!( + concat!( + "invalid argument list in `default(", + stringify!($($args)*), + ")`", + ) + ) + }; + // Print an error if there is an unexpected token after `default`. + (@case + (default $t:tt $($tail:tt)*) + $cases:tt + $default:tt + ) => { + compile_error!( + concat!( + "expected an argument list or `=>` after `default`, found `", + stringify!($t), + "`", + ) + ) + }; + + // The case was not consumed, therefore it must be invalid. + (@case + ($case:ident $($tail:tt)*) + $cases:tt + $default:tt + ) => { + compile_error!( + concat!( + "expected one of `recv`, `send`, or `default`, found `", + stringify!($case), + "`", + ) + ) + }; + + // Optimize `select!` into `try_recv()`. + (@init + (recv($r:expr) -> $res:pat => $recv_body:tt,) + (default() => $default_body:tt,) + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + match _r.try_recv() { + ::std::result::Result::Err($crate::TryRecvError::Empty) => { + $default_body + } + _res => { + let _res = _res.map_err(|_| $crate::RecvError); + let $res = _res; + $recv_body + } + } + } + } + }}; + // Optimize `select!` into `recv()`. + (@init + (recv($r:expr) -> $res:pat => $body:tt,) + () + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + let _res = _r.recv(); + let $res = _res; + $body + } + } + }}; + // Optimize `select!` into `recv_timeout()`. + (@init + (recv($r:expr) -> $res:pat => $recv_body:tt,) + (default($timeout:expr) => $default_body:tt,) + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + match _r.recv_timeout($timeout) { + ::std::result::Result::Err($crate::RecvTimeoutError::Timeout) => { + $default_body + } + _res => { + let _res = _res.map_err(|_| $crate::RecvError); + let $res = _res; + $recv_body + } + } + } + } + }}; + + // // Optimize the non-blocking case with two receive operations. + // (@init + // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,) + // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,) + // (default() => $default_body:tt,) + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + // // Optimize the blocking case with two receive operations. + // (@init + // (recv($r1:expr) -> $res1:pat => $body1:tt,) + // (recv($r2:expr) -> $res2:pat => $body2:tt,) + // () + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + // // Optimize the case with two receive operations and a timeout. + // (@init + // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,) + // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,) + // (default($timeout:expr) => $default_body:tt,) + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + + // // Optimize `select!` into `try_send()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,) + // (default() => $default_body:tt,) + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + // // Optimize `select!` into `send()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $body:tt,) + // () + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + // // Optimize `select!` into `send_timeout()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $body:tt,) + // (default($timeout:expr) => $body:tt,) + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + + // Create the list of handles and add operations to it. + (@init + ($($cases:tt)*) + $default:tt + ) => {{ + const _LEN: usize = $crate::crossbeam_channel_internal!(@count ($($cases)*)); + let _handle: &$crate::internal::SelectHandle = &$crate::never::<()>(); + + #[allow(unused_mut)] + let mut _sel = [(_handle, 0, ::std::ptr::null()); _LEN]; + + $crate::crossbeam_channel_internal!( + @add + _sel + ($($cases)*) + $default + ( + (0usize _oper0) + (1usize _oper1) + (2usize _oper2) + (3usize _oper3) + (4usize _oper4) + (5usize _oper5) + (6usize _oper6) + (7usize _oper7) + (8usize _oper8) + (9usize _oper9) + (10usize _oper10) + (11usize _oper11) + (12usize _oper12) + (13usize _oper13) + (14usize _oper14) + (15usize _oper15) + (16usize _oper16) + (17usize _oper17) + (18usize _oper18) + (19usize _oper19) + (20usize _oper20) + (21usize _oper21) + (22usize _oper22) + (23usize _oper23) + (24usize _oper24) + (25usize _oper25) + (26usize _oper26) + (27usize _oper27) + (28usize _oper28) + (29usize _oper29) + (30usize _oper30) + (31usize _oper31) + ) + () + ) + }}; + + // Count the listed cases. + (@count ()) => { + 0 + }; + (@count ($oper:ident $args:tt -> $res:pat => $body:tt, $($cases:tt)*)) => { + 1 + $crate::crossbeam_channel_internal!(@count ($($cases)*)) + }; + + // Run blocking selection. + (@add + $sel:ident + () + () + $labels:tt + $cases:tt + ) => {{ + let _oper: $crate::SelectedOperation<'_> = { + let _oper = $crate::internal::select(&mut $sel); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe { ::std::mem::transmute(_oper) } + }; + + $crate::crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + }}; + // Run non-blocking selection. + (@add + $sel:ident + () + (default() => $body:tt,) + $labels:tt + $cases:tt + ) => {{ + let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = { + let _oper = $crate::internal::try_select(&mut $sel); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe { ::std::mem::transmute(_oper) } + }; + + match _oper { + None => { + { $sel }; + $body + } + Some(_oper) => { + $crate::crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + } + } + }}; + // Run selection with a timeout. + (@add + $sel:ident + () + (default($timeout:expr) => $body:tt,) + $labels:tt + $cases:tt + ) => {{ + let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = { + let _oper = $crate::internal::select_timeout(&mut $sel, $timeout); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe { ::std::mem::transmute(_oper) } + }; + + match _oper { + ::std::option::Option::None => { + { $sel }; + $body + } + ::std::option::Option::Some(_oper) => { + $crate::crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + } + } + }}; + // Have we used up all labels? + (@add + $sel:ident + $input:tt + $default:tt + () + $cases:tt + ) => { + compile_error!("too many operations in a `select!` block") + }; + // Add a receive operation to `sel`. + (@add + $sel:ident + (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) + $default:tt + (($i:tt $var:ident) $($labels:tt)*) + ($($cases:tt)*) + ) => {{ + match $r { + ref _r => { + let $var: &$crate::Receiver<_> = unsafe { + let _r: &$crate::Receiver<_> = _r; + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe fn unbind<'a, T>(x: &T) -> &'a T { + ::std::mem::transmute(x) + } + unbind(_r) + }; + $sel[$i] = ($var, $i, $var as *const $crate::Receiver<_> as *const u8); + + $crate::crossbeam_channel_internal!( + @add + $sel + ($($tail)*) + $default + ($($labels)*) + ($($cases)* [$i] recv($var) -> $res => $body,) + ) + } + } + }}; + // Add a send operation to `sel`. + (@add + $sel:ident + (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + $default:tt + (($i:tt $var:ident) $($labels:tt)*) + ($($cases:tt)*) + ) => {{ + match $s { + ref _s => { + let $var: &$crate::Sender<_> = unsafe { + let _s: &$crate::Sender<_> = _s; + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe fn unbind<'a, T>(x: &T) -> &'a T { + ::std::mem::transmute(x) + } + unbind(_s) + }; + $sel[$i] = ($var, $i, $var as *const $crate::Sender<_> as *const u8); + + $crate::crossbeam_channel_internal!( + @add + $sel + ($($tail)*) + $default + ($($labels)*) + ($($cases)* [$i] send($var, $m) -> $res => $body,) + ) + } + } + }}; + + // Complete a receive operation. + (@complete + $sel:ident + $oper:ident + ([$i:tt] recv($r:ident) -> $res:pat => $body:tt, $($tail:tt)*) + ) => {{ + if $oper.index() == $i { + let _res = $oper.recv($r); + { $sel }; + + let $res = _res; + $body + } else { + $crate::crossbeam_channel_internal! { + @complete + $sel + $oper + ($($tail)*) + } + } + }}; + // Complete a send operation. + (@complete + $sel:ident + $oper:ident + ([$i:tt] send($s:ident, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ) => {{ + if $oper.index() == $i { + let _res = $oper.send($s, $m); + { $sel }; + + let $res = _res; + $body + } else { + $crate::crossbeam_channel_internal! { + @complete + $sel + $oper + ($($tail)*) + } + } + }}; + // Panic if we don't identify the selected case, but this should never happen. + (@complete + $sel:ident + $oper:ident + () + ) => {{ + unreachable!( + "internal error in crossbeam-channel: invalid case" + ) + }}; + + // Catches a bug within this macro (should not happen). + (@$($tokens:tt)*) => { + compile_error!( + concat!( + "internal error in crossbeam-channel: ", + stringify!(@$($tokens)*), + ) + ) + }; + + // The entry points. + () => { + compile_error!("empty `select!` block") + }; + ($($case:ident $(($($args:tt)*))* => $body:expr $(,)*)*) => { + $crate::crossbeam_channel_internal!( + @list + ($($case $(($($args)*))* => { $body },)*) + () + ) + }; + ($($tokens:tt)*) => { + $crate::crossbeam_channel_internal!( + @list + ($($tokens)*) + () + ) + }; +} + +/// Selects from a set of channel operations. +/// +/// This macro allows you to define a set of channel operations, wait until any one of them becomes +/// ready, and finally execute it. If multiple operations are ready at the same time, a random one +/// among them is selected. +/// +/// It is also possible to define a `default` case that gets executed if none of the operations are +/// ready, either right away or for a certain duration of time. +/// +/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even +/// when it will simply return an error because the channel is disconnected. +/// +/// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a +/// dynamically created list of channel operations. +/// +/// [`Select`]: super::Select +/// +/// # Examples +/// +/// Block until a send or a receive operation is selected: +/// +/// ``` +/// use crossbeam_channel::{select, unbounded}; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// s1.send(10).unwrap(); +/// +/// // Since both operations are initially ready, a random one will be executed. +/// select! { +/// recv(r1) -> msg => assert_eq!(msg, Ok(10)), +/// send(s2, 20) -> res => { +/// assert_eq!(res, Ok(())); +/// assert_eq!(r2.recv(), Ok(20)); +/// } +/// } +/// ``` +/// +/// Select from a set of operations without blocking: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::{select, unbounded}; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // None of the operations are initially ready. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2) -> msg => panic!(), +/// default => println!("not ready"), +/// } +/// ``` +/// +/// Select over a set of operations with a timeout: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::{select, unbounded}; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // None of the two operations will become ready within 100 milliseconds. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2) -> msg => panic!(), +/// default(Duration::from_millis(100)) => println!("timed out"), +/// } +/// ``` +/// +/// Optionally add a receive operation to `select!` using [`never`]: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::{select, never, unbounded}; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // This receiver can be a `Some` or a `None`. +/// let r2 = Some(&r2); +/// +/// // None of the two operations will become ready within 100 milliseconds. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)), +/// } +/// ``` +/// +/// To optionally add a timeout to `select!`, see the [example] for [`never`]. +/// +/// [`never`]: super::never +/// [example]: super::never#examples +#[macro_export] +macro_rules! select { + ($($tokens:tt)*) => { + $crate::crossbeam_channel_internal!( + $($tokens)* + ) + }; +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/utils.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/utils.rs new file mode 100644 index 0000000..3fe171b --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/utils.rs @@ -0,0 +1,112 @@ +//! Miscellaneous utilities. + +use std::cell::{Cell, UnsafeCell}; +use std::num::Wrapping; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_utils::Backoff; + +/// Randomly shuffles a slice. +pub fn shuffle(v: &mut [T]) { + let len = v.len(); + if len <= 1 { + return; + } + + thread_local! { + static RNG: Cell> = Cell::new(Wrapping(1_406_868_647)); + } + + let _ = RNG.try_with(|rng| { + for i in 1..len { + // This is the 32-bit variant of Xorshift. + // + // Source: https://en.wikipedia.org/wiki/Xorshift + let mut x = rng.get(); + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + rng.set(x); + + let x = x.0; + let n = i + 1; + + // This is a fast alternative to `let j = x % n`. + // + // Author: Daniel Lemire + // Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + let j = ((x as u64).wrapping_mul(n as u64) >> 32) as u32 as usize; + + v.swap(i, j); + } + }); +} + +/// Sleeps until the deadline, or forever if the deadline isn't specified. +pub fn sleep_until(deadline: Option) { + loop { + match deadline { + None => thread::sleep(Duration::from_secs(1000)), + Some(d) => { + let now = Instant::now(); + if now >= d { + break; + } + thread::sleep(d - now); + } + } + } +} + +/// A simple spinlock. +pub struct Spinlock { + flag: AtomicBool, + value: UnsafeCell, +} + +impl Spinlock { + /// Returns a new spinlock initialized with `value`. + pub fn new(value: T) -> Spinlock { + Spinlock { + flag: AtomicBool::new(false), + value: UnsafeCell::new(value), + } + } + + /// Locks the spinlock. + pub fn lock(&self) -> SpinlockGuard<'_, T> { + let backoff = Backoff::new(); + while self.flag.swap(true, Ordering::Acquire) { + backoff.snooze(); + } + SpinlockGuard { parent: self } + } +} + +/// A guard holding a spinlock locked. +pub struct SpinlockGuard<'a, T> { + parent: &'a Spinlock, +} + +impl Drop for SpinlockGuard<'_, T> { + fn drop(&mut self) { + self.parent.flag.store(false, Ordering::Release); + } +} + +impl Deref for SpinlockGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.parent.value.get() } + } +} + +impl DerefMut for SpinlockGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.parent.value.get() } + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/waker.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/waker.rs new file mode 100644 index 0000000..3d0af26 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/src/waker.rs @@ -0,0 +1,287 @@ +//! Waking mechanism for threads blocked on channel operations. + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread::{self, ThreadId}; + +use crate::context::Context; +use crate::select::{Operation, Selected}; +use crate::utils::Spinlock; + +/// Represents a thread blocked on a specific channel operation. +pub struct Entry { + /// The operation. + pub oper: Operation, + + /// Optional packet. + pub packet: usize, + + /// Context associated with the thread owning this operation. + pub cx: Context, +} + +/// A queue of threads blocked on channel operations. +/// +/// This data structure is used by threads to register blocking operations and get woken up once +/// an operation becomes ready. +pub struct Waker { + /// A list of select operations. + selectors: Vec, + + /// A list of operations waiting to be ready. + observers: Vec, +} + +impl Waker { + /// Creates a new `Waker`. + #[inline] + pub fn new() -> Self { + Waker { + selectors: Vec::new(), + observers: Vec::new(), + } + } + + /// Registers a select operation. + #[inline] + pub fn register(&mut self, oper: Operation, cx: &Context) { + self.register_with_packet(oper, 0, cx); + } + + /// Registers a select operation and a packet. + #[inline] + pub fn register_with_packet(&mut self, oper: Operation, packet: usize, cx: &Context) { + self.selectors.push(Entry { + oper, + packet, + cx: cx.clone(), + }); + } + + /// Unregisters a select operation. + #[inline] + pub fn unregister(&mut self, oper: Operation) -> Option { + if let Some((i, _)) = self + .selectors + .iter() + .enumerate() + .find(|&(_, entry)| entry.oper == oper) + { + let entry = self.selectors.remove(i); + Some(entry) + } else { + None + } + } + + /// Attempts to find another thread's entry, select the operation, and wake it up. + #[inline] + pub fn try_select(&mut self) -> Option { + let mut entry = None; + + if !self.selectors.is_empty() { + let thread_id = current_thread_id(); + + for i in 0..self.selectors.len() { + // Does the entry belong to a different thread? + if self.selectors[i].cx.thread_id() != thread_id { + // Try selecting this operation. + let sel = Selected::Operation(self.selectors[i].oper); + let res = self.selectors[i].cx.try_select(sel); + + if res.is_ok() { + // Provide the packet. + self.selectors[i].cx.store_packet(self.selectors[i].packet); + // Wake the thread up. + self.selectors[i].cx.unpark(); + + // Remove the entry from the queue to keep it clean and improve + // performance. + entry = Some(self.selectors.remove(i)); + break; + } + } + } + } + + entry + } + + /// Returns `true` if there is an entry which can be selected by the current thread. + #[inline] + pub fn can_select(&self) -> bool { + if self.selectors.is_empty() { + false + } else { + let thread_id = current_thread_id(); + + self.selectors.iter().any(|entry| { + entry.cx.thread_id() != thread_id && entry.cx.selected() == Selected::Waiting + }) + } + } + + /// Registers an operation waiting to be ready. + #[inline] + pub fn watch(&mut self, oper: Operation, cx: &Context) { + self.observers.push(Entry { + oper, + packet: 0, + cx: cx.clone(), + }); + } + + /// Unregisters an operation waiting to be ready. + #[inline] + pub fn unwatch(&mut self, oper: Operation) { + self.observers.retain(|e| e.oper != oper); + } + + /// Notifies all operations waiting to be ready. + #[inline] + pub fn notify(&mut self) { + for entry in self.observers.drain(..) { + if entry.cx.try_select(Selected::Operation(entry.oper)).is_ok() { + entry.cx.unpark(); + } + } + } + + /// Notifies all registered operations that the channel is disconnected. + #[inline] + pub fn disconnect(&mut self) { + for entry in self.selectors.iter() { + if entry.cx.try_select(Selected::Disconnected).is_ok() { + // Wake the thread up. + // + // Here we don't remove the entry from the queue. Registered threads must + // unregister from the waker by themselves. They might also want to recover the + // packet value and destroy it, if necessary. + entry.cx.unpark(); + } + } + + self.notify(); + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + debug_assert_eq!(self.selectors.len(), 0); + debug_assert_eq!(self.observers.len(), 0); + } +} + +/// A waker that can be shared among threads without locking. +/// +/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization. +pub struct SyncWaker { + /// The inner `Waker`. + inner: Spinlock, + + /// `true` if the waker is empty. + is_empty: AtomicBool, +} + +impl SyncWaker { + /// Creates a new `SyncWaker`. + #[inline] + pub fn new() -> Self { + SyncWaker { + inner: Spinlock::new(Waker::new()), + is_empty: AtomicBool::new(true), + } + } + + /// Registers the current thread with an operation. + #[inline] + pub fn register(&self, oper: Operation, cx: &Context) { + let mut inner = self.inner.lock(); + inner.register(oper, cx); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Unregisters an operation previously registered by the current thread. + #[inline] + pub fn unregister(&self, oper: Operation) -> Option { + let mut inner = self.inner.lock(); + let entry = inner.unregister(oper); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + entry + } + + /// Attempts to find one thread (not the current one), select its operation, and wake it up. + #[inline] + pub fn notify(&self) { + if !self.is_empty.load(Ordering::SeqCst) { + let mut inner = self.inner.lock(); + if !self.is_empty.load(Ordering::SeqCst) { + inner.try_select(); + inner.notify(); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + } + } + + /// Registers an operation waiting to be ready. + #[inline] + pub fn watch(&self, oper: Operation, cx: &Context) { + let mut inner = self.inner.lock(); + inner.watch(oper, cx); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Unregisters an operation waiting to be ready. + #[inline] + pub fn unwatch(&self, oper: Operation) { + let mut inner = self.inner.lock(); + inner.unwatch(oper); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Notifies all threads that the channel is disconnected. + #[inline] + pub fn disconnect(&self) { + let mut inner = self.inner.lock(); + inner.disconnect(); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } +} + +impl Drop for SyncWaker { + #[inline] + fn drop(&mut self) { + debug_assert_eq!(self.is_empty.load(Ordering::SeqCst), true); + } +} + +/// Returns the id of the current thread. +#[inline] +fn current_thread_id() -> ThreadId { + thread_local! { + /// Cached thread-local id. + static THREAD_ID: ThreadId = thread::current().id(); + } + + THREAD_ID + .try_with(|id| *id) + .unwrap_or_else(|_| thread::current().id()) +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/after.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/after.rs new file mode 100644 index 0000000..20670dc --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/after.rs @@ -0,0 +1,334 @@ +//! Tests for the after channel flavor. + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, select, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn fire() { + let start = Instant::now(); + let r = after(ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(100)); + + let fired = r.try_recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired >= ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + + select! { + recv(r) -> _ => panic!(), + recv(after(ms(200))) -> _ => {} + } +} + +#[test] +fn capacity() { + const COUNT: usize = 10; + + for i in 0..COUNT { + let r = after(ms(i as u64)); + assert_eq!(r.capacity(), Some(1)); + } +} + +#[test] +fn len_empty_full() { + let r = after(ms(50)); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + thread::sleep(ms(100)); + + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.try_recv().unwrap(); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let r = after(ms(200)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv() { + let start = Instant::now(); + let r = after(ms(50)); + + let fired = r.recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired < fired - start); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = after(ms(200)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(200)); + assert!(fired - start <= ms(250)); + + assert!(r.recv_timeout(ms(200)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(400)); + assert!(now - start <= ms(450)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_two() { + let r1 = after(ms(50)); + let r2 = after(ms(50)); + + scope(|scope| { + scope.spawn(|_| { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + }); + scope.spawn(|_| { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_race() { + select! { + recv(after(ms(50))) -> _ => {} + recv(after(ms(100))) -> _ => panic!(), + } + + select! { + recv(after(ms(100))) -> _ => panic!(), + recv(after(ms(50))) -> _ => {} + } +} + +#[test] +fn stress_default() { + const COUNT: usize = 10; + + for _ in 0..COUNT { + select! { + recv(after(ms(0))) -> _ => {} + default => panic!(), + } + } + + for _ in 0..COUNT { + select! { + recv(after(ms(100))) -> _ => panic!(), + default => {} + } + } +} + +#[test] +fn select() { + const THREADS: usize = 4; + const COUNT: usize = 1000; + const TIMEOUT_MS: u64 = 100; + + let v = (0..COUNT) + .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) + .collect::>(); + let hits = AtomicUsize::new(0); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let v: Vec<&_> = v.iter().collect(); + + loop { + let timeout = after(ms(TIMEOUT_MS)); + let mut sel = Select::new(); + for r in &v { + sel.recv(r); + } + let oper_timeout = sel.recv(&timeout); + + let oper = sel.select(); + match oper.index() { + i if i == oper_timeout => { + oper.recv(&timeout).unwrap(); + break; + } + i => { + oper.recv(&v[i]).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), COUNT); +} + +#[test] +fn ready() { + const THREADS: usize = 4; + const COUNT: usize = 1000; + const TIMEOUT_MS: u64 = 100; + + let v = (0..COUNT) + .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) + .collect::>(); + let hits = AtomicUsize::new(0); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let v: Vec<&_> = v.iter().collect(); + + loop { + let timeout = after(ms(TIMEOUT_MS)); + let mut sel = Select::new(); + for r in &v { + sel.recv(r); + } + let oper_timeout = sel.recv(&timeout); + + loop { + let i = sel.ready(); + if i == oper_timeout { + timeout.try_recv().unwrap(); + return; + } else if v[i].try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), COUNT); +} + +#[test] +fn stress_clone() { + const RUNS: usize = 1000; + const THREADS: usize = 10; + const COUNT: usize = 50; + + for i in 0..RUNS { + let r = after(ms(i as u64)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let r = r.clone(); + let _ = r.try_recv(); + + for _ in 0..COUNT { + drop(r.clone()); + thread::yield_now(); + } + }); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness() { + const COUNT: usize = 1000; + + for &dur in &[0, 1] { + let mut hits = [0usize; 2]; + + for _ in 0..COUNT { + select! { + recv(after(ms(dur))) -> _ => hits[0] += 1, + recv(after(ms(dur))) -> _ => hits[1] += 1, + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 1000; + + for &dur in &[0, 1] { + let mut hits = [0usize; 5]; + + for _ in 0..COUNT { + let r = after(ms(dur)); + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/array.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/array.rs new file mode 100644 index 0000000..a7ae323 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/array.rs @@ -0,0 +1,654 @@ +//! Tests for the array channel flavor. + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, select, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = bounded(1); + s.send(7).unwrap(); + assert_eq!(r.try_recv(), Ok(7)); + + s.send(8).unwrap(); + assert_eq!(r.recv(), Ok(8)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); +} + +#[test] +fn capacity() { + for i in 1..10 { + let (s, r) = bounded::<()>(i); + assert_eq!(s.capacity(), Some(i)); + assert_eq!(r.capacity(), Some(i)); + } +} + +#[test] +fn len_empty_full() { + let (s, r) = bounded(2); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 2); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 2); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.recv().unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let (s, r) = bounded(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.try_send(1), Ok(())); + assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); + thread::sleep(ms(1500)); + assert_eq!(s.try_send(3), Ok(())); + thread::sleep(ms(500)); + assert_eq!(s.try_send(4), Err(TrySendError::Disconnected(4))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.try_recv(), Ok(1)); + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv(), Ok(3)); + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| { + s.send(7).unwrap(); + thread::sleep(ms(1000)); + s.send(8).unwrap(); + thread::sleep(ms(1000)); + s.send(9).unwrap(); + thread::sleep(ms(1000)); + s.send(10).unwrap(); + }); + scope.spawn(|_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(7)); + assert_eq!(r.recv(), Ok(8)); + assert_eq!(r.recv(), Ok(9)); + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send_timeout(1, ms(1000)), Ok(())); + assert_eq!(s.send_timeout(2, ms(1000)), Ok(())); + assert_eq!( + s.send_timeout(3, ms(500)), + Err(SendTimeoutError::Timeout(3)) + ); + thread::sleep(ms(1000)); + assert_eq!(s.send_timeout(4, ms(1000)), Ok(())); + thread::sleep(ms(1000)); + assert_eq!(s.send(5), Err(SendError(5))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(1)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(4)); + }); + }) + .unwrap(); +} + +#[test] +fn send_after_disconnect() { + let (s, r) = bounded(100); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(r); + + assert_eq!(s.send(4), Err(SendError(4))); + assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); + assert_eq!( + s.send_timeout(6, ms(500)), + Err(SendTimeoutError::Disconnected(6)) + ); +} + +#[test] +fn recv_after_disconnect() { + let (s, r) = bounded(100); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(s); + + assert_eq!(r.recv(), Ok(1)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(3)); + assert_eq!(r.recv(), Err(RecvError)); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + const CAP: usize = 1000; + + let (s, r) = bounded(CAP); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for _ in 0..CAP / 10 { + for i in 0..50 { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for i in 0..50 { + r.recv().unwrap(); + assert_eq!(r.len(), 50 - i - 1); + } + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for i in 0..CAP { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for _ in 0..CAP { + r.recv().unwrap(); + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + let len = r.len(); + assert!(len <= CAP); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + let len = s.len(); + assert!(len <= CAP); + } + }); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send(()), Ok(())); + assert_eq!(s.send(()), Err(SendError(()))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = bounded(3); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded::(3); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 100_000; + + let (request_s, request_r) = bounded(1); + let (response_s, response_r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(()) = s.send_timeout(i, ms(10)) { + break; + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + const RUNS: usize = 100; + + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..RUNS { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 50); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = bounded::(50); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + s.send(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded(THREADS); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + s.send(0).unwrap(); + r.try_recv().unwrap(); + } + }); + } + }) + .unwrap(); +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = bounded::<()>(COUNT); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = bounded::<()>(COUNT); + + for _ in 0..COUNT { + s.send(()).unwrap(); + } + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn recv_in_send() { + let (s, _r) = bounded(1); + s.send(()).unwrap(); + + #[allow(unreachable_code)] + { + select! { + send(s, panic!()) -> _ => panic!(), + default => {} + } + } + + let (s, r) = bounded(2); + s.send(()).unwrap(); + + select! { + send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = bounded::(1); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(1); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/golang.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/golang.rs new file mode 100644 index 0000000..69a9315 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/golang.rs @@ -0,0 +1,1511 @@ +//! Tests copied from Go and manually rewritten in Rust. +//! +//! Source: +//! - https://github.com/golang/go +//! +//! Copyright & License: +//! - Copyright (c) 2009 The Go Authors +//! - https://golang.org/AUTHORS +//! - https://golang.org/LICENSE +//! - https://golang.org/PATENTS + +use std::alloc::{GlobalAlloc, Layout, System}; +use std::any::Any; +use std::cell::Cell; +use std::collections::HashMap; +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, select, tick, unbounded, Receiver, Select, Sender}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +struct Chan { + inner: Arc>>, +} + +struct ChanInner { + s: Option>, + r: Receiver, +} + +impl Clone for Chan { + fn clone(&self) -> Chan { + Chan { + inner: self.inner.clone(), + } + } +} + +impl Chan { + fn send(&self, msg: T) { + let s = self + .inner + .lock() + .unwrap() + .s + .as_ref() + .expect("sending into closed channel") + .clone(); + let _ = s.send(msg); + } + + fn try_recv(&self) -> Option { + let r = self.inner.lock().unwrap().r.clone(); + r.try_recv().ok() + } + + fn recv(&self) -> Option { + let r = self.inner.lock().unwrap().r.clone(); + r.recv().ok() + } + + fn close(&self) { + self.inner + .lock() + .unwrap() + .s + .take() + .expect("channel already closed"); + } + + fn rx(&self) -> Receiver { + self.inner.lock().unwrap().r.clone() + } + + fn tx(&self) -> Sender { + match self.inner.lock().unwrap().s.as_ref() { + None => { + let (s, r) = bounded(0); + std::mem::forget(r); + s + } + Some(s) => s.clone(), + } + } +} + +impl Iterator for Chan { + type Item = T; + + fn next(&mut self) -> Option { + self.recv() + } +} + +impl<'a, T> IntoIterator for &'a Chan { + type Item = T; + type IntoIter = Chan; + + fn into_iter(self) -> Self::IntoIter { + self.clone() + } +} + +fn make(cap: usize) -> Chan { + let (s, r) = bounded(cap); + Chan { + inner: Arc::new(Mutex::new(ChanInner { s: Some(s), r })), + } +} + +fn make_unbounded() -> Chan { + let (s, r) = unbounded(); + Chan { + inner: Arc::new(Mutex::new(ChanInner { s: Some(s), r })), + } +} +#[derive(Clone)] +struct WaitGroup(Arc); + +struct WaitGroupInner { + cond: Condvar, + count: Mutex, +} + +impl WaitGroup { + fn new() -> WaitGroup { + WaitGroup(Arc::new(WaitGroupInner { + cond: Condvar::new(), + count: Mutex::new(0), + })) + } + + fn add(&self, delta: i32) { + let mut count = self.0.count.lock().unwrap(); + *count += delta; + assert!(*count >= 0); + self.0.cond.notify_all(); + } + + fn done(&self) { + self.add(-1); + } + + fn wait(&self) { + let mut count = self.0.count.lock().unwrap(); + while *count > 0 { + count = self.0.cond.wait(count).unwrap(); + } + } +} + +struct Defer { + f: Option>, +} + +impl Drop for Defer { + fn drop(&mut self) { + let f = self.f.take().unwrap(); + let mut f = Some(f); + let mut f = move || f.take().unwrap()(); + f(); + } +} + +struct Counter; + +static ALLOCATED: AtomicUsize = AtomicUsize::new(0); +unsafe impl GlobalAlloc for Counter { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let ret = System.alloc(layout); + if !ret.is_null() { + ALLOCATED.fetch_add(layout.size(), SeqCst); + } + return ret; + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + System.dealloc(ptr, layout); + ALLOCATED.fetch_sub(layout.size(), SeqCst); + } +} + +#[global_allocator] +static A: Counter = Counter; + +macro_rules! defer { + ($body:expr) => { + let _defer = Defer { + f: Some(Box::new(|| $body)), + }; + }; +} + +macro_rules! go { + (@parse ref $v:ident, $($tail:tt)*) => {{ + let ref $v = $v; + go!(@parse $($tail)*) + }}; + (@parse move $v:ident, $($tail:tt)*) => {{ + let $v = $v; + go!(@parse $($tail)*) + }}; + (@parse $v:ident, $($tail:tt)*) => {{ + let $v = $v.clone(); + go!(@parse $($tail)*) + }}; + (@parse $body:expr) => { + ::std::thread::spawn(move || { + let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| { + $body + })); + if res.is_err() { + eprintln!("goroutine panicked: {:?}", res); + ::std::process::abort(); + } + }) + }; + (@parse $($tail:tt)*) => { + compile_error!("invalid `go!` syntax") + }; + ($($tail:tt)*) => {{ + go!(@parse $($tail)*) + }}; +} + +// https://github.com/golang/go/blob/master/test/chan/doubleselect.go +mod doubleselect { + use super::*; + + const ITERATIONS: i32 = 10_000; + + fn sender(n: i32, c1: Chan, c2: Chan, c3: Chan, c4: Chan) { + defer! { c1.close() } + defer! { c2.close() } + defer! { c3.close() } + defer! { c4.close() } + + for i in 0..n { + select! { + send(c1.tx(), i) -> _ => {} + send(c2.tx(), i) -> _ => {} + send(c3.tx(), i) -> _ => {} + send(c4.tx(), i) -> _ => {} + } + } + } + + fn mux(out: Chan, inp: Chan, done: Chan) { + for v in inp { + out.send(v); + } + done.send(true); + } + + fn recver(inp: Chan) { + let mut seen = HashMap::new(); + + for v in &inp { + if seen.contains_key(&v) { + panic!("got duplicate value for {}", v); + } + seen.insert(v, true); + } + } + + #[test] + fn main() { + let c1 = make::(0); + let c2 = make::(0); + let c3 = make::(0); + let c4 = make::(0); + let done = make::(0); + let cmux = make::(0); + + go!(c1, c2, c3, c4, sender(ITERATIONS, c1, c2, c3, c4)); + go!(cmux, c1, done, mux(cmux, c1, done)); + go!(cmux, c2, done, mux(cmux, c2, done)); + go!(cmux, c3, done, mux(cmux, c3, done)); + go!(cmux, c4, done, mux(cmux, c4, done)); + go!(done, cmux, { + done.recv(); + done.recv(); + done.recv(); + done.recv(); + cmux.close(); + }); + recver(cmux); + } +} + +// https://github.com/golang/go/blob/master/test/chan/fifo.go +mod fifo { + use super::*; + + const N: i32 = 10; + + #[test] + fn asynch_fifo() { + let ch = make::(N as usize); + for i in 0..N { + ch.send(i); + } + for i in 0..N { + if ch.recv() != Some(i) { + panic!("bad receive"); + } + } + } + + fn chain(ch: Chan, val: i32, inp: Chan, out: Chan) { + inp.recv(); + if ch.recv() != Some(val) { + panic!(val); + } + out.send(1); + } + + #[test] + fn synch_fifo() { + let ch = make::(0); + let mut inp = make::(0); + let start = inp.clone(); + + for i in 0..N { + let out = make::(0); + go!(ch, i, inp, out, chain(ch, i, inp, out)); + inp = out; + } + + start.send(0); + for i in 0..N { + ch.send(i); + } + inp.recv(); + } +} + +// https://github.com/golang/go/blob/master/test/chan/goroutines.go +mod goroutines { + use super::*; + + fn f(left: Chan, right: Chan) { + left.send(right.recv().unwrap()); + } + + #[test] + fn main() { + let n = 100i32; + + let leftmost = make::(0); + let mut right = leftmost.clone(); + let mut left = leftmost.clone(); + + for _ in 0..n { + right = make::(0); + go!(left, right, f(left, right)); + left = right.clone(); + } + + go!(right, right.send(1)); + leftmost.recv().unwrap(); + } +} + +// https://github.com/golang/go/blob/master/test/chan/nonblock.go +mod nonblock { + use super::*; + + fn i32receiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != 123 { + panic!("i32 value"); + } + strobe.send(true); + } + + fn i32sender(c: Chan, strobe: Chan) { + c.send(234); + strobe.send(true); + } + + fn i64receiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != 123456 { + panic!("i64 value"); + } + strobe.send(true); + } + + fn i64sender(c: Chan, strobe: Chan) { + c.send(234567); + strobe.send(true); + } + + fn breceiver(c: Chan, strobe: Chan) { + if !c.recv().unwrap() { + panic!("b value"); + } + strobe.send(true); + } + + fn bsender(c: Chan, strobe: Chan) { + c.send(true); + strobe.send(true); + } + + fn sreceiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != "hello" { + panic!("x value"); + } + strobe.send(true); + } + + fn ssender(c: Chan, strobe: Chan) { + c.send("hello again".to_string()); + strobe.send(true); + } + + const MAX_TRIES: usize = 10000; // Up to 100ms per test. + + #[test] + fn main() { + let ticker = tick(Duration::new(0, 10_000)); // 10 us + let sleep = || { + ticker.recv().unwrap(); + ticker.recv().unwrap(); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + }; + + let sync = make::(0); + + for buffer in 0..2 { + let c32 = make::(buffer); + let c64 = make::(buffer); + let cb = make::(buffer); + let cs = make::(buffer); + + select! { + recv(c32.rx()) -> _ => panic!("blocked i32sender"), + default => {} + } + + select! { + recv(c64.rx()) -> _ => panic!("blocked i64sender"), + default => {} + } + + select! { + recv(cb.rx()) -> _ => panic!("blocked bsender"), + default => {} + } + + select! { + recv(cs.rx()) -> _ => panic!("blocked ssender"), + default => {} + } + + go!(c32, sync, i32receiver(c32, sync)); + let mut r#try = 0; + loop { + select! { + send(c32.tx(), 123) -> _ => break, + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("i32receiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(c32, sync, i32sender(c32, sync)); + if buffer > 0 { + sync.recv(); + } + let mut r#try = 0; + loop { + select! { + recv(c32.rx()) -> v => { + if v != Ok(234) { + panic!("i32sender value"); + } + break; + } + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("i32sender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(c64, sync, i64receiver(c64, sync)); + let mut r#try = 0; + loop { + select! { + send(c64.tx(), 123456) -> _ => break, + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("i64receiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(c64, sync, i64sender(c64, sync)); + if buffer > 0 { + sync.recv(); + } + let mut r#try = 0; + loop { + select! { + recv(c64.rx()) -> v => { + if v != Ok(234567) { + panic!("i64sender value"); + } + break; + } + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("i64sender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(cb, sync, breceiver(cb, sync)); + let mut r#try = 0; + loop { + select! { + send(cb.tx(), true) -> _ => break, + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("breceiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(cb, sync, bsender(cb, sync)); + if buffer > 0 { + sync.recv(); + } + let mut r#try = 0; + loop { + select! { + recv(cb.rx()) -> v => { + if v != Ok(true) { + panic!("bsender value"); + } + break; + } + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("bsender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(cs, sync, sreceiver(cs, sync)); + let mut r#try = 0; + loop { + select! { + send(cs.tx(), "hello".to_string()) -> _ => break, + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("sreceiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(cs, sync, ssender(cs, sync)); + if buffer > 0 { + sync.recv(); + } + let mut r#try = 0; + loop { + select! { + recv(cs.rx()) -> v => { + if v != Ok("hello again".to_string()) { + panic!("ssender value"); + } + break; + } + default => { + r#try += 1; + if r#try > MAX_TRIES { + println!("ssender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/select.go +mod select { + use super::*; + + #[test] + fn main() { + let shift = Cell::new(0); + let counter = Cell::new(0); + + let get_value = || { + counter.set(counter.get() + 1); + 1 << shift.get() + }; + + let send = |mut a: Option<&Chan>, mut b: Option<&Chan>| { + let mut i = 0; + let never = make::(0); + loop { + let nil1 = never.tx(); + let nil2 = never.tx(); + let v1 = get_value(); + let v2 = get_value(); + select! { + send(a.map(|c| c.tx()).unwrap_or(nil1), v1) -> _ => { + i += 1; + a = None; + } + send(b.map(|c| c.tx()).unwrap_or(nil2), v2) -> _ => { + i += 1; + b = None; + } + default => break, + } + shift.set(shift.get() + 1); + } + i + }; + + let a = make::(1); + let b = make::(1); + + assert_eq!(send(Some(&a), Some(&b)), 2); + + let av = a.recv().unwrap(); + let bv = b.recv().unwrap(); + assert_eq!(av | bv, 3); + + assert_eq!(send(Some(&a), None), 1); + assert_eq!(counter.get(), 10); + } +} + +// https://github.com/golang/go/blob/master/test/chan/select2.go +mod select2 { + use super::*; + + #[test] + fn main() { + fn sender(c: &Chan, n: i32) { + for _ in 0..n { + c.send(1); + } + } + + fn receiver(c: &Chan, dummy: &Chan, n: i32) { + for _ in 0..n { + select! { + recv(c.rx()) -> _ => { + () + } + recv(dummy.rx()) -> _ => { + panic!("dummy"); + } + } + } + } + + let c = make_unbounded::(); + let dummy = make_unbounded::(); + + ALLOCATED.store(0, SeqCst); + + go!(c, sender(&c, 100000)); + receiver(&c, &dummy, 100000); + + let alloc = ALLOCATED.load(SeqCst); + + go!(c, sender(&c, 100000)); + receiver(&c, &dummy, 100000); + + assert!(!(ALLOCATED.load(SeqCst) > alloc && (ALLOCATED.load(SeqCst) - alloc) > 110000)) + } +} + +// https://github.com/golang/go/blob/master/test/chan/select3.go +mod select3 { + // TODO +} + +// https://github.com/golang/go/blob/master/test/chan/select4.go +mod select4 { + use super::*; + + #[test] + fn main() { + let c = make::(1); + let c1 = make::(0); + c.send(42); + select! { + recv(c1.rx()) -> _ => panic!("BUG"), + recv(c.rx()) -> v => assert_eq!(v, Ok(42)), + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/select6.go +mod select6 { + use super::*; + + #[test] + fn main() { + let c1 = make::(0); + let c2 = make::(0); + let c3 = make::(0); + + go!(c1, c1.recv()); + go!(c1, c2, c3, { + select! { + recv(c1.rx()) -> _ => panic!("dummy"), + recv(c2.rx()) -> _ => c3.send(true), + } + c1.recv(); + }); + go!(c2, c2.send(true)); + + c3.recv(); + c1.send(true); + c1.send(true); + } +} + +// https://github.com/golang/go/blob/master/test/chan/select7.go +mod select7 { + use super::*; + + fn recv1(c: Chan) { + c.recv().unwrap(); + } + + fn recv2(c: Chan) { + select! { + recv(c.rx()) -> _ => () + } + } + + fn recv3(c: Chan) { + let c2 = make::(1); + select! { + recv(c.rx()) -> _ => (), + recv(c2.rx()) -> _ => () + } + } + + fn send1(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + c.send(1); + } + + fn send2(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + select! { + send(c.tx(), 1) -> _ => () + } + } + + fn send3(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + let c2 = make::(1); + select! { + send(c.tx(), 1) -> _ => (), + send(c2.tx(), 1) -> _ => () + } + } + + #[test] + fn main() { + send1(recv1); + send2(recv1); + send3(recv1); + send1(recv2); + send2(recv2); + send3(recv2); + send1(recv3); + send2(recv3); + send3(recv3); + } +} + +// https://github.com/golang/go/blob/master/test/chan/sieve1.go +mod sieve1 { + use super::*; + + fn generate(ch: Chan) { + let mut i = 2; + loop { + ch.send(i); + i += 1; + } + } + + fn filter(in_ch: Chan, out_ch: Chan, prime: i32) { + for i in in_ch { + if i % prime != 0 { + out_ch.send(i); + } + } + } + + fn sieve(primes: Chan) { + let mut ch = make::(1); + go!(ch, generate(ch)); + loop { + let prime = ch.recv().unwrap(); + primes.send(prime); + + let ch1 = make::(1); + go!(ch, ch1, prime, filter(ch, ch1, prime)); + ch = ch1; + } + } + + #[test] + fn main() { + let primes = make::(1); + go!(primes, sieve(primes)); + + let a = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, + ]; + for item in a.iter() { + let x = primes.recv().unwrap(); + if x != *item { + println!("{} != {}", x, item); + panic!("fail"); + } + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/zerosize.go +mod zerosize { + use super::*; + + #[test] + fn zero_size_struct() { + struct ZeroSize; + let _ = make::(0); + } + + #[test] + fn zero_size_array() { + let _ = make::<[u8; 0]>(0); + } +} + +// https://github.com/golang/go/blob/master/src/runtime/chan_test.go +mod chan_test { + use super::*; + + #[test] + fn test_chan() { + const N: i32 = 200; + + for cap in 0..N { + { + // Ensure that receive from empty chan blocks. + let c = make::(cap as usize); + + let recv1 = Arc::new(Mutex::new(false)); + go!(c, recv1, { + c.recv(); + *recv1.lock().unwrap() = true; + }); + + let recv2 = Arc::new(Mutex::new(false)); + go!(c, recv2, { + c.recv(); + *recv2.lock().unwrap() = true; + }); + + thread::sleep(ms(1)); + + if *recv1.lock().unwrap() || *recv2.lock().unwrap() { + panic!(); + } + + // Ensure that non-blocking receive does not block. + select! { + recv(c.rx()) -> _ => panic!(), + default => {} + } + select! { + recv(c.rx()) -> _ => panic!(), + default => {} + } + + c.send(0); + c.send(0); + } + + { + // Ensure that send to full chan blocks. + let c = make::(cap as usize); + for i in 0..cap { + c.send(i); + } + + let sent = Arc::new(Mutex::new(0)); + go!(sent, c, { + c.send(0); + *sent.lock().unwrap() = 1; + }); + + thread::sleep(ms(1)); + + if *sent.lock().unwrap() != 0 { + panic!(); + } + + // Ensure that non-blocking send does not block. + select! { + send(c.tx(), 0) -> _ => panic!(), + default => {} + } + c.recv(); + } + + { + // Ensure that we receive 0 from closed chan. + let c = make::(cap as usize); + for i in 0..cap { + c.send(i); + } + c.close(); + + for i in 0..cap { + let v = c.recv(); + if v != Some(i) { + panic!(); + } + } + + if c.recv() != None { + panic!(); + } + if c.try_recv() != None { + panic!(); + } + } + + { + // Ensure that close unblocks receive. + let c = make::(cap as usize); + let done = make::(0); + + go!(c, done, { + let v = c.try_recv(); + done.send(v.is_none()); + }); + + thread::sleep(ms(1)); + c.close(); + + if !done.recv().unwrap() { + panic!(); + } + } + + { + // Send 100 integers, + // ensure that we receive them non-corrupted in FIFO order. + let c = make::(cap as usize); + go!(c, { + for i in 0..100 { + c.send(i); + } + }); + for i in 0..100 { + if c.recv() != Some(i) { + panic!(); + } + } + + // Same, but using recv2. + go!(c, { + for i in 0..100 { + c.send(i); + } + }); + for i in 0..100 { + if c.recv() != Some(i) { + panic!(); + } + } + } + } + } + + #[test] + fn test_nonblock_recv_race() { + const N: usize = 1000; + + for _ in 0..N { + let c = make::(1); + c.send(1); + + let t = go!(c, { + select! { + recv(c.rx()) -> _ => {} + default => panic!("chan is not ready"), + } + }); + + c.close(); + c.recv(); + t.join().unwrap(); + } + } + + #[test] + fn test_nonblock_select_race() { + const N: usize = 1000; + + let done = make::(1); + for _ in 0..N { + let c1 = make::(1); + let c2 = make::(1); + c1.send(1); + + go!(c1, c2, done, { + select! { + recv(c1.rx()) -> _ => {} + recv(c2.rx()) -> _ => {} + default => { + done.send(false); + return; + } + } + done.send(true); + }); + + c2.send(1); + select! { + recv(c1.rx()) -> _ => {} + default => {} + } + if !done.recv().unwrap() { + panic!("no chan is ready"); + } + } + } + + #[test] + fn test_nonblock_select_race2() { + const N: usize = 1000; + + let done = make::(1); + for _ in 0..N { + let c1 = make::(1); + let c2 = make::(0); + c1.send(1); + + go!(c1, c2, done, { + select! { + recv(c1.rx()) -> _ => {} + recv(c2.rx()) -> _ => {} + default => { + done.send(false); + return; + } + } + done.send(true); + }); + + c2.close(); + select! { + recv(c1.rx()) -> _ => {} + default => {} + } + if !done.recv().unwrap() { + panic!("no chan is ready"); + } + } + } + + #[test] + fn test_self_select() { + // Ensure that send/recv on the same chan in select + // does not crash nor deadlock. + + for &cap in &[0, 10] { + let wg = WaitGroup::new(); + wg.add(2); + let c = make::(cap); + + for p in 0..2 { + let p = p; + go!(wg, p, c, { + defer! { wg.done() } + for i in 0..1000 { + if p == 0 || i % 2 == 0 { + select! { + send(c.tx(), p) -> _ => {} + recv(c.rx()) -> v => { + if cap == 0 && v.ok() == Some(p) { + panic!("self receive"); + } + } + } + } else { + select! { + recv(c.rx()) -> v => { + if cap == 0 && v.ok() == Some(p) { + panic!("self receive"); + } + } + send(c.tx(), p) -> _ => {} + } + } + } + }); + } + wg.wait(); + } + } + + #[test] + fn test_select_stress() { + let c = vec![ + make::(0), + make::(0), + make::(2), + make::(3), + ]; + + const N: usize = 10000; + + // There are 4 goroutines that send N values on each of the chans, + // + 4 goroutines that receive N values on each of the chans, + // + 1 goroutine that sends N values on each of the chans in a single select, + // + 1 goroutine that receives N values on each of the chans in a single select. + // All these sends, receives and selects interact chaotically at runtime, + // but we are careful that this whole construct does not deadlock. + let wg = WaitGroup::new(); + wg.add(10); + + for k in 0..4 { + go!(k, c, wg, { + for _ in 0..N { + c[k].send(0); + } + wg.done(); + }); + go!(k, c, wg, { + for _ in 0..N { + c[k].recv(); + } + wg.done(); + }); + } + + go!(c, wg, { + let mut n = [0; 4]; + let mut c1 = c.iter().map(|c| Some(c.rx().clone())).collect::>(); + + for _ in 0..4 * N { + let index = { + let mut sel = Select::new(); + let mut opers = [!0; 4]; + for &i in &[3, 2, 0, 1] { + if let Some(c) = &c1[i] { + opers[i] = sel.recv(c); + } + } + + let oper = sel.select(); + let mut index = !0; + for i in 0..4 { + if opers[i] == oper.index() { + index = i; + let _ = oper.recv(c1[i].as_ref().unwrap()); + break; + } + } + index + }; + + n[index] += 1; + if n[index] == N { + c1[index] = None; + } + } + wg.done(); + }); + + go!(c, wg, { + let mut n = [0; 4]; + let mut c1 = c.iter().map(|c| Some(c.tx().clone())).collect::>(); + + for _ in 0..4 * N { + let index = { + let mut sel = Select::new(); + let mut opers = [!0; 4]; + for &i in &[0, 1, 2, 3] { + if let Some(c) = &c1[i] { + opers[i] = sel.send(c); + } + } + + let oper = sel.select(); + let mut index = !0; + for i in 0..4 { + if opers[i] == oper.index() { + index = i; + let _ = oper.send(c1[i].as_ref().unwrap(), 0); + break; + } + } + index + }; + + n[index] += 1; + if n[index] == N { + c1[index] = None; + } + } + wg.done(); + }); + + wg.wait(); + } + + #[test] + fn test_select_fairness() { + const TRIALS: usize = 10000; + + let c1 = make::(TRIALS + 1); + let c2 = make::(TRIALS + 1); + + for _ in 0..TRIALS + 1 { + c1.send(1); + c2.send(2); + } + + let c3 = make::(0); + let c4 = make::(0); + let out = make::(0); + let done = make::(0); + let wg = WaitGroup::new(); + + wg.add(1); + go!(wg, c1, c2, c3, c4, out, done, { + defer! { wg.done() }; + loop { + let b; + select! { + recv(c3.rx()) -> m => b = m.unwrap(), + recv(c4.rx()) -> m => b = m.unwrap(), + recv(c1.rx()) -> m => b = m.unwrap(), + recv(c2.rx()) -> m => b = m.unwrap(), + } + select! { + send(out.tx(), b) -> _ => {} + recv(done.rx()) -> _ => return, + } + } + }); + + let (mut cnt1, mut cnt2) = (0, 0); + for _ in 0..TRIALS { + match out.recv() { + Some(1) => cnt1 += 1, + Some(2) => cnt2 += 1, + b => panic!("unexpected value {:?} on channel", b), + } + } + + // If the select in the goroutine is fair, + // cnt1 and cnt2 should be about the same value. + // With 10,000 trials, the expected margin of error at + // a confidence level of five nines is 4.4172 / (2 * Sqrt(10000)). + + let r = cnt1 as f64 / TRIALS as f64; + let e = (r - 0.5).abs(); + + if e > 4.4172 / (2.0 * (TRIALS as f64).sqrt()) { + panic!( + "unfair select: in {} trials, results were {}, {}", + TRIALS, cnt1, cnt2, + ); + } + + done.close(); + wg.wait(); + } + + #[test] + fn test_chan_send_interface() { + struct Mt; + + let c = make::>(1); + c.send(Box::new(Mt)); + + select! { + send(c.tx(), Box::new(Mt)) -> _ => {} + default => {} + } + + select! { + send(c.tx(), Box::new(Mt)) -> _ => {} + send(c.tx(), Box::new(Mt)) -> _ => {} + default => {} + } + } + + #[test] + fn test_pseudo_random_send() { + const N: usize = 100; + + for cap in 0..N { + let c = make::(cap); + let l = Arc::new(Mutex::new(vec![0i32; N])); + let done = make::(0); + + go!(c, done, l, { + let mut l = l.lock().unwrap(); + for i in 0..N { + thread::yield_now(); + l[i] = c.recv().unwrap(); + } + done.send(true); + }); + + for _ in 0..N { + select! { + send(c.tx(), 1) -> _ => {} + send(c.tx(), 0) -> _ => {} + } + } + done.recv(); + + let mut n0 = 0; + let mut n1 = 0; + for &i in l.lock().unwrap().iter() { + n0 += (i + 1) % 2; + n1 += i; + } + + if n0 <= N as i32 / 10 || n1 <= N as i32 / 10 { + panic!( + "Want pseudorandom, got {} zeros and {} ones (chan cap {})", + n0, n1, cap, + ); + } + } + } + + #[test] + fn test_multi_consumer() { + const NWORK: usize = 23; + const NITER: usize = 271828; + + let pn = [2, 3, 7, 11, 13, 17, 19, 23, 27, 31]; + + let q = make::(NWORK * 3); + let r = make::(NWORK * 3); + + let wg = WaitGroup::new(); + for i in 0..NWORK { + wg.add(1); + let w = i; + go!(q, r, wg, pn, { + for v in &q { + if pn[w % pn.len()] == v { + thread::yield_now(); + } + r.send(v); + } + wg.done(); + }); + } + + let expect = Arc::new(Mutex::new(0)); + go!(q, r, expect, wg, pn, { + for i in 0..NITER { + let v = pn[i % pn.len()]; + *expect.lock().unwrap() += v; + q.send(v); + } + q.close(); + wg.wait(); + r.close(); + }); + + let mut n = 0; + let mut s = 0; + for v in &r { + n += 1; + s += v; + } + + if n != NITER || s != *expect.lock().unwrap() { + panic!(); + } + } + + #[test] + fn test_select_duplicate_channel() { + // This test makes sure we can queue a G on + // the same channel multiple times. + let c = make::(0); + let d = make::(0); + let e = make::(0); + + go!(c, d, e, { + select! { + recv(c.rx()) -> _ => {} + recv(d.rx()) -> _ => {} + recv(e.rx()) -> _ => {} + } + e.send(9); + }); + thread::sleep(ms(1)); + + go!(c, c.recv()); + thread::sleep(ms(1)); + + d.send(7); + e.recv(); + c.send(8); + } +} + +// https://github.com/golang/go/blob/master/test/closedchan.go +mod closedchan { + // TODO +} + +// https://github.com/golang/go/blob/master/src/runtime/chanbarrier_test.go +mod chanbarrier_test { + // TODO +} + +// https://github.com/golang/go/blob/master/src/runtime/race/testdata/chan_test.go +mod race_chan_test { + // TODO +} + +// https://github.com/golang/go/blob/master/test/ken/chan.go +mod chan { + // TODO +} + +// https://github.com/golang/go/blob/master/test/ken/chan1.go +mod chan1 { + // TODO +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/iter.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/iter.rs new file mode 100644 index 0000000..38bcac2 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/iter.rs @@ -0,0 +1,110 @@ +//! Tests for iteration over receivers. + +use crossbeam_channel::unbounded; +use crossbeam_utils::thread::scope; + +#[test] +fn nested_recv_iter() { + let (s, r) = unbounded::(); + let (total_s, total_r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + let mut acc = 0; + for x in r.iter() { + acc += x; + } + total_s.send(acc).unwrap(); + }); + + s.send(3).unwrap(); + s.send(1).unwrap(); + s.send(2).unwrap(); + drop(s); + assert_eq!(total_r.recv().unwrap(), 6); + }) + .unwrap(); +} + +#[test] +fn recv_iter_break() { + let (s, r) = unbounded::(); + let (count_s, count_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + for x in r.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_s.send(count).unwrap(); + }); + + s.send(2).unwrap(); + s.send(2).unwrap(); + s.send(2).unwrap(); + let _ = s.send(2); + drop(s); + assert_eq!(count_r.recv().unwrap(), 4); + }) + .unwrap(); +} + +#[test] +fn recv_try_iter() { + let (request_s, request_r) = unbounded(); + let (response_s, response_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == 6 { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(2).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn recv_into_iter_owned() { + let mut iter = { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + r.into_iter() + }; + + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn recv_into_iter_borrowed() { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + drop(s); + + let mut iter = (&r).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/list.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/list.rs new file mode 100644 index 0000000..8b84105 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/list.rs @@ -0,0 +1,533 @@ +//! Tests for the list channel flavor. + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{select, unbounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = unbounded(); + s.try_send(7).unwrap(); + assert_eq!(r.try_recv(), Ok(7)); + + s.send(8).unwrap(); + assert_eq!(r.recv(), Ok(8)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); +} + +#[test] +fn capacity() { + let (s, r) = unbounded::<()>(); + assert_eq!(s.capacity(), None); + assert_eq!(r.capacity(), None); +} + +#[test] +fn len_empty_full() { + let (s, r) = unbounded(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); + + r.recv().unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.try_send(i), Ok(())); + } + + drop(r); + assert_eq!(s.try_send(777), Err(TrySendError::Disconnected(777))); +} + +#[test] +fn send() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.send(i), Ok(())); + } + + drop(r); + assert_eq!(s.send(777), Err(SendError(777))); +} + +#[test] +fn send_timeout() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.send_timeout(i, ms(i as u64)), Ok(())); + } + + drop(r); + assert_eq!( + s.send_timeout(777, ms(0)), + Err(SendTimeoutError::Disconnected(777)) + ); +} + +#[test] +fn send_after_disconnect() { + let (s, r) = unbounded(); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(r); + + assert_eq!(s.send(4), Err(SendError(4))); + assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); + assert_eq!( + s.send_timeout(6, ms(0)), + Err(SendTimeoutError::Disconnected(6)) + ); +} + +#[test] +fn recv_after_disconnect() { + let (s, r) = unbounded(); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(s); + + assert_eq!(r.recv(), Ok(1)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(3)); + assert_eq!(r.recv(), Err(RecvError)); +} + +#[test] +fn len() { + let (s, r) = unbounded(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for i in 0..50 { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for i in 0..50 { + r.recv().unwrap(); + assert_eq!(r.len(), 50 - i - 1); + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = unbounded::(); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 100_000; + + let (request_s, request_r) = unbounded(); + let (response_s, response_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + s.send(i).unwrap(); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..100 { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 1000); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + s.try_send(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = unbounded(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + s.send(0).unwrap(); + r.try_recv().unwrap(); + } + }); + } + }) + .unwrap(); +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = unbounded(); + + for _ in 0..COUNT { + s.send(()).unwrap(); + } + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn recv_in_send() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + select! { + send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = unbounded(); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/mpsc.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/mpsc.rs new file mode 100644 index 0000000..2a0786a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/mpsc.rs @@ -0,0 +1,2094 @@ +//! Tests copied from `std::sync::mpsc`. +//! +//! This is a copy of tests for the `std::sync::mpsc` channels from the standard library, but +//! modified to work with `crossbeam-channel` instead. +//! +//! Minor tweaks were needed to make the tests compile: +//! +//! - Replace `box` syntax with `Box::new`. +//! - Replace all uses of `Select` with `select!`. +//! - Change the imports. +//! - Join all spawned threads. +//! - Removed assertion from oneshot_multi_thread_send_close_stress tests. +//! +//! Source: +//! - https://github.com/rust-lang/rust/tree/master/src/libstd/sync/mpsc +//! +//! Copyright & License: +//! - Copyright 2013-2014 The Rust Project Developers +//! - Apache License, Version 2.0 or MIT license, at your option +//! - https://github.com/rust-lang/rust/blob/master/COPYRIGHT +//! - https://www.rust-lang.org/en-US/legal.html + +use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; +use std::sync::mpsc::{SendError, TrySendError}; +use std::thread::JoinHandle; +use std::time::Duration; + +use crossbeam_channel as cc; + +pub struct Sender { + pub inner: cc::Sender, +} + +impl Sender { + pub fn send(&self, t: T) -> Result<(), SendError> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } +} + +impl Clone for Sender { + fn clone(&self) -> Sender { + Sender { + inner: self.inner.clone(), + } + } +} + +pub struct SyncSender { + pub inner: cc::Sender, +} + +impl SyncSender { + pub fn send(&self, t: T) -> Result<(), SendError> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } + + pub fn try_send(&self, t: T) -> Result<(), TrySendError> { + self.inner.try_send(t).map_err(|err| match err { + cc::TrySendError::Full(m) => TrySendError::Full(m), + cc::TrySendError::Disconnected(m) => TrySendError::Disconnected(m), + }) + } +} + +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + SyncSender { + inner: self.inner.clone(), + } + } +} + +pub struct Receiver { + pub inner: cc::Receiver, +} + +impl Receiver { + pub fn try_recv(&self) -> Result { + self.inner.try_recv().map_err(|err| match err { + cc::TryRecvError::Empty => TryRecvError::Empty, + cc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + pub fn recv(&self) -> Result { + self.inner.recv().map_err(|_| RecvError) + } + + pub fn recv_timeout(&self, timeout: Duration) -> Result { + self.inner.recv_timeout(timeout).map_err(|err| match err { + cc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout, + cc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } + + pub fn iter(&self) -> Iter { + Iter { inner: self } + } + + pub fn try_iter(&self) -> TryIter { + TryIter { inner: self } + } +} + +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { inner: self } + } +} + +pub struct TryIter<'a, T: 'a> { + inner: &'a Receiver, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.try_recv().ok() + } +} + +pub struct Iter<'a, T: 'a> { + inner: &'a Receiver, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.recv().ok() + } +} + +pub struct IntoIter { + inner: Receiver, +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.recv().ok() + } +} + +pub fn channel() -> (Sender, Receiver) { + let (s, r) = cc::unbounded(); + let s = Sender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { + let (s, r) = cc::bounded(bound); + let s = SyncSender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +macro_rules! select { + ( + $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ + ) => ({ + cc::crossbeam_channel_internal! { + $( + recv(($rx).inner) -> res => { + let $name = res.map_err(|_| ::std::sync::mpsc::RecvError); + $code + } + )+ + } + }) +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs +mod channel_tests { + use super::*; + + use std::env; + use std::thread; + use std::time::{Duration, Instant}; + + pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } + } + + #[test] + fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn smoke_threads() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); + t.join().unwrap(); + } + + #[test] + fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); + } + + #[test] + fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} + t.join().unwrap(); + } + + #[test] + fn stress() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().unwrap(); + } + + #[test] + fn stress_shared() { + const AMT: u32 = 10000; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + let mut ts = Vec::with_capacity(NTHREADS as usize); + for _ in 0..NTHREADS { + let tx = tx.clone(); + let t = thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + drop(tx); + t.join().ok().unwrap(); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); + } + + #[test] + fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().unwrap(); + } + + #[test] + fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); + } + + #[test] + fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); + } + + #[test] + fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); + } + + #[test] + fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + drop(tx); + }); + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_thread_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + drop(tx); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + thread::spawn(move || { + let _ = tx.send(1); + }) + .join() + .unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_recv_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + }); + ts.push(t); + let t2 = thread::spawn(move || { + let t = thread::spawn(move || { + drop(tx); + }); + t.join().unwrap(); + }); + ts.push(t2); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + ts.push(t); + assert!(*rx.recv().unwrap() == 10); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn stream_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel(); + + if let Some(t) = send(tx, 0) { + ts.push(t); + } + if let Some(t2) = recv(rx, 0) { + ts.push(t2); + } + + fn send(tx: Sender>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + })) + } + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + } + + #[test] + fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + let t = thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); + t.join().unwrap() + } + + #[test] + fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); + } + + #[test] + fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + let mut ts = Vec::with_capacity(stress); + for i in 0..stress { + let tx = tx.clone(); + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + ts.push(t); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } + } + + #[test] + fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); + t.join().unwrap(); + } + + #[test] + fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); + t.join().unwrap(); + } + + #[test] + fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); + } + + #[test] + fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); + } + + #[test] + fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); + } + + #[test] + fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + t.join().unwrap(); + } + + // This bug used to end up in a livelock inside of the Receiver destructor + // because the internal state of the Shared packet was corrupted + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let tx2 = tx.clone(); + drop(tx); + tx2.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); + } +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs +mod sync_channel_tests { + use super::*; + + use std::env; + use std::thread; + use std::time::Duration; + + pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } + } + + #[test] + fn smoke() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = sync_channel::>(1); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn recv_timeout() { + let (tx, rx) = sync_channel::(1); + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(1).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); + } + + #[test] + fn smoke_threads() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); + t.join().unwrap(); + } + + #[test] + fn smoke_port_gone() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = sync_channel::(0); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn port_gone_concurrent_shared() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn smoke_chan_gone() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn smoke_chan_gone_shared() { + let (tx, rx) = sync_channel::<()>(0); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); + } + + #[test] + fn chan_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} + t.join().unwrap(); + } + + #[test] + fn stress() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().unwrap(); + } + + #[test] + fn stress_recv_timeout_two_threads() { + let (tx, rx) = sync_channel::(0); + + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(1)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, 10000); + t.join().unwrap(); + } + + #[test] + fn stress_recv_timeout_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + let t = thread::spawn(move || { + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, AMT * NTHREADS); + assert!(rx.try_recv().is_err()); + + dtx.send(()).unwrap(); + }); + + let mut ts = Vec::with_capacity(NTHREADS as usize); + for _ in 0..NTHREADS { + let tx = tx.clone(); + let t = thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + + drop(tx); + + drx.recv().unwrap(); + for t in ts { + t.join().unwrap(); + } + t.join().unwrap(); + } + + #[test] + fn stress_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + dtx.send(()).unwrap(); + }); + + let mut ts = Vec::with_capacity(NTHREADS as usize); + for _ in 0..NTHREADS { + let tx = tx.clone(); + let t = thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + drop(tx); + drx.recv().unwrap(); + for t in ts { + t.join().unwrap(); + } + t.join().unwrap(); + } + + #[test] + fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = sync_channel::(0); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = sync_channel::(0); + drop(tx); + } + + #[test] + fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = sync_channel::>(0); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = sync_channel::>(1); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(10), Ok(())); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); + } + + #[test] + fn oneshot_single_thread_try_send_closed2() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_closed_with_data() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + drop(tx); + assert_eq!(rx.try_recv(), Ok(10)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); + } + + #[test] + fn oneshot_single_thread_peek_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_open() { + let (_tx, rx) = sync_channel::(0); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + drop(tx); + }); + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_thread_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + drop(tx); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + thread::spawn(move || { + let _ = tx.send(1); + }) + .join() + .unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_recv_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + }); + ts.push(t); + let t2 = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + ts.push(t2); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + ts.push(t); + assert!(*rx.recv().unwrap() == 10); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn stream_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::>(0); + + if let Some(t) = send(tx, 0) { + ts.push(t); + } + if let Some(t) = recv(rx, 0) { + ts.push(t); + } + + fn send(tx: SyncSender>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + })) + } + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = sync_channel(10000); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } + } + + #[test] + fn shared_chan_stress() { + let (tx, rx) = sync_channel(0); + let total = stress_factor() + 100; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn test_nested_recv_iter() { + let (tx, rx) = sync_channel::(0); + let (total_tx, total_rx) = sync_channel::(0); + + let t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); + t.join().unwrap(); + } + + #[test] + fn test_recv_iter_break() { + let (tx, rx) = sync_channel::(0); + let (count_tx, count_rx) = sync_channel(0); + + let t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.try_send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); + t.join().unwrap(); + } + + #[test] + fn try_recv_states() { + let (tx1, rx1) = sync_channel::(1); + let (tx2, rx2) = sync_channel::<()>(1); + let (tx3, rx3) = sync_channel::<()>(1); + let t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + t.join().unwrap(); + } + + // This bug used to end up in a livelock inside of the Receiver destructor + // because the internal state of the Shared packet was corrupted + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = sync_channel::<()>(0); + let (tx2, rx2) = sync_channel::<()>(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let tx2 = tx.clone(); + drop(tx); + tx2.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn send1() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + assert_eq!(tx.send(1), Ok(())); + t.join().unwrap(); + } + + #[test] + fn send2() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); + t.join().unwrap(); + } + + #[test] + fn send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.send(1), Ok(())); + let t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); + t.join().unwrap(); + } + + #[test] + fn send4() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let (done, donerx) = channel(); + let done2 = done.clone(); + let t = thread::spawn(move || { + assert!(tx.send(1).is_err()); + done.send(()).unwrap(); + }); + let t2 = thread::spawn(move || { + assert!(tx2.send(2).is_err()); + done2.send(()).unwrap(); + }); + drop(rx); + donerx.recv().unwrap(); + donerx.recv().unwrap(); + t.join().unwrap(); + t2.join().unwrap(); + } + + #[test] + fn try_send1() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send2() { + let (tx, _rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + drop(rx); + assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); + } + + #[test] + fn issue_15761() { + fn repro() { + let (tx1, rx1) = sync_channel::<()>(3); + let (tx2, rx2) = sync_channel::<()>(3); + + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + tx2.try_send(()).unwrap(); + }); + + tx1.try_send(()).unwrap(); + rx2.recv().unwrap(); + } + + for _ in 0..100 { + repro() + } + } +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/select.rs +mod select_tests { + use super::*; + + use std::thread; + + #[test] + fn smoke() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + tx1.send(1).unwrap(); + select! { + foo = rx1.recv() => assert_eq!(foo.unwrap(), 1), + _bar = rx2.recv() => panic!() + } + tx2.send(2).unwrap(); + select! { + _foo = rx1.recv() => panic!(), + bar = rx2.recv() => assert_eq!(bar.unwrap(), 2) + } + drop(tx1); + select! { + foo = rx1.recv() => assert!(foo.is_err()), + _bar = rx2.recv() => panic!() + } + drop(tx2); + select! { + bar = rx2.recv() => assert!(bar.is_err()) + } + } + + #[test] + fn smoke2() { + let (_tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (_tx3, rx3) = channel::(); + let (_tx4, rx4) = channel::(); + let (tx5, rx5) = channel::(); + tx5.send(4).unwrap(); + select! { + _foo = rx1.recv() => panic!("1"), + _foo = rx2.recv() => panic!("2"), + _foo = rx3.recv() => panic!("3"), + _foo = rx4.recv() => panic!("4"), + foo = rx5.recv() => assert_eq!(foo.unwrap(), 4) + } + } + + #[test] + fn closed() { + let (_tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + drop(tx2); + + select! { + _a1 = rx1.recv() => panic!(), + a2 = rx2.recv() => assert!(a2.is_err()) + } + } + + #[test] + fn unblocks() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..20 { + thread::yield_now(); + } + tx1.send(1).unwrap(); + rx3.recv().unwrap(); + for _ in 0..20 { + thread::yield_now(); + } + }); + + select! { + a = rx1.recv() => assert_eq!(a.unwrap(), 1), + _b = rx2.recv() => panic!() + } + tx3.send(1).unwrap(); + select! { + a = rx1.recv() => assert!(a.is_err()), + _b = rx2.recv() => panic!() + } + t.join().unwrap(); + } + + #[test] + fn both_ready() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + for _ in 0..20 { + thread::yield_now(); + } + tx1.send(1).unwrap(); + tx2.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } + } + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } + } + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[test] + fn stress() { + const AMT: i32 = 10000; + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + for i in 0..AMT { + if i % 2 == 0 { + tx1.send(i).unwrap(); + } else { + tx2.send(i).unwrap(); + } + rx3.recv().unwrap(); + } + }); + + for i in 0..AMT { + select! { + i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, + i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } + } + tx3.send(()).unwrap(); + } + t.join().unwrap(); + } + + #[allow(unused_must_use)] + #[test] + fn cloning() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + rx3.recv().unwrap(); + tx1.clone(); + assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); + tx1.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + tx3.send(()).unwrap(); + select! { + _i1 = rx1.recv() => {}, + _i2 = rx2.recv() => panic!() + } + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[allow(unused_must_use)] + #[test] + fn cloning2() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + rx3.recv().unwrap(); + tx1.clone(); + assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); + tx1.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + tx3.send(()).unwrap(); + select! { + _i1 = rx1.recv() => {}, + _i2 = rx2.recv() => panic!() + } + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[test] + fn cloning3() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let t = thread::spawn(move || { + select! { + _ = rx1.recv() => panic!(), + _ = rx2.recv() => {} + } + tx3.send(()).unwrap(); + }); + + for _ in 0..1000 { + thread::yield_now(); + } + drop(tx1.clone()); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn preflight1() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight2() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight3() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight4() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight5() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight6() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight7() { + let (tx, rx) = channel::<()>(); + drop(tx); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight8() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + drop(tx); + rx.recv().unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight9() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + drop(tx); + rx.recv().unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn oneshot_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn stream_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + tx1.send(()).unwrap(); + tx1.send(()).unwrap(); + rx1.recv().unwrap(); + rx1.recv().unwrap(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn shared_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + drop(tx1.clone()); + tx1.send(()).unwrap(); + rx1.recv().unwrap(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn sync1() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + } + + #[test] + fn sync2() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + for _ in 0..100 { + thread::yield_now() + } + tx.send(1).unwrap(); + }); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + t.join().unwrap(); + } + + #[test] + fn sync3() { + let (tx1, rx1) = sync_channel::(0); + let (tx2, rx2): (Sender, Receiver) = channel(); + let t = thread::spawn(move || { + tx1.send(1).unwrap(); + }); + let t2 = thread::spawn(move || { + tx2.send(2).unwrap(); + }); + select! { + n = rx1.recv() => { + let n = n.unwrap(); + assert_eq!(n, 1); + assert_eq!(rx2.recv().unwrap(), 2); + }, + n = rx2.recv() => { + let n = n.unwrap(); + assert_eq!(n, 2); + assert_eq!(rx1.recv().unwrap(), 1); + } + } + t.join().unwrap(); + t2.join().unwrap(); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/never.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/never.rs new file mode 100644 index 0000000..31cebf6 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/never.rs @@ -0,0 +1,95 @@ +//! Tests for the never channel flavor. + +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{never, select, tick, unbounded}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + select! { + recv(never::()) -> _ => panic!(), + default => {} + } +} + +#[test] +fn optional() { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + + let mut r = Some(&r); + select! { + recv(r.unwrap_or(&never())) -> _ => {} + default => panic!(), + } + + r = None; + select! { + recv(r.unwrap_or(&never())) -> _ => panic!(), + default => {} + } +} + +#[test] +fn tick_n() { + let mut r = tick(ms(100)); + let mut step = 0; + + loop { + select! { + recv(r) -> _ => step += 1, + default(ms(500)) => break, + } + + if step == 10 { + r = never(); + } + } + + assert_eq!(step, 10); +} + +#[test] +fn capacity() { + let r = never::(); + assert_eq!(r.capacity(), Some(0)); +} + +#[test] +fn len_empty_full() { + let r = never::(); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); +} + +#[test] +fn try_recv() { + let r = never::(); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = never::(); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(200)); + assert!(now - start <= ms(250)); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/ready.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/ready.rs new file mode 100644 index 0000000..700f487 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/ready.rs @@ -0,0 +1,834 @@ +//! Tests for channel readiness using the `Select` struct. + +use std::any::Any; +use std::cell::Cell; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, tick, unbounded}; +use crossbeam_channel::{Receiver, Select, TryRecvError, TrySendError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert_eq!(sel.ready(), 0); + assert_eq!(r1.try_recv(), Ok(1)); + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert_eq!(sel.ready(), 1); + assert_eq!(r2.try_recv(), Ok(2)); +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&r3); + sel.recv(&r4); + sel.recv(&r5); + assert_eq!(sel.ready(), 4); + assert_eq!(r5.try_recv(), Ok(5)); +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + r2.recv().unwrap(); + }) + .unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + let mut sel = Select::new(); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r2.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert!(sel.try_ready().is_err()); + + drop(s1); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.try_ready() { + Ok(0) => assert!(r1.try_recv().is_err()), + _ => panic!(), + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r2); + match sel.try_ready() { + Ok(0) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + + let mut sel = Select::new(); + sel.recv(&r2); + assert!(sel.try_ready().is_err()); + + let mut sel = Select::new(); + assert!(sel.try_ready().is_err()); +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert!(sel.ready_timeout(ms(1000)).is_err()); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + let mut sel = Select::new(); + assert!(sel.ready_timeout(ms(1000)).is_err()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.try_ready() { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.try_ready() { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + sel.send(&s); + match sel.try_ready() { + Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), + _ => panic!(), + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), + _ => panic!(), + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + + let mut sel = Select::new(); + assert!(sel.try_ready().is_err()); + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + let mut sel = Select::new(); + assert!(sel.ready_timeout(ms(500)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => oper.send(&s1, 1).unwrap(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.send(&s2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(1)), + 1 => s2.try_send(2).unwrap(), + _ => panic!(), + } + } + }) + .unwrap(); +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert!(r3.try_recv().is_err()); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => drop(r1.try_recv()), + 1 => drop(r2.try_recv()), + _ => panic!(), + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => panic!(), + 1 => drop(r2.try_recv()), + _ => panic!(), + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => drop(r.try_recv()), + _ => panic!(), + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => assert_eq!(r.try_recv(), Ok(())), + _ => panic!(), + } + + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let hit = vec![Cell::new(false); 4]; + + while hit.iter().map(|h| h.get()).any(|hit| !hit) { + let mut sel = Select::new(); + sel.recv(&r); + sel.recv(&r); + sel.send(&s); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(r.try_recv().is_ok()); + hit[0].set(true); + } + 1 => { + assert!(r.try_recv().is_ok()); + hit[1].set(true); + } + 2 => { + assert!(s.try_send(0).is_ok()); + hit[2].set(true); + } + 3 => { + assert!(s.try_send(0).is_ok()); + hit[3].set(true); + } + _ => panic!(), + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(s.try_send(0).is_ok()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => { + assert_eq!(r.try_recv(), Ok(0)); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(s.try_send(1).is_ok()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => { + assert_eq!(r.try_recv(), Ok(1)); + } + _ => panic!(), + } + } + _ => panic!(), + } + } + _ => panic!(), + } + } + _ => panic!(), + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(i)), + 1 => assert_eq!(r2.try_recv(), Ok(i)), + _ => panic!(), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.send(&s1); + sel.send(&s2); + match sel.ready() { + 0 => assert!(s1.try_send(i).is_ok()), + 1 => assert!(s2.try_send(i).is_ok()), + _ => panic!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.send(&s2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(i)), + 1 => assert!(s2.try_send(i).is_ok()), + _ => panic!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let done = false; + while !done { + let mut sel = Select::new(); + sel.send(&s); + match sel.ready_timeout(ms(100)) { + Err(_) => {} + Ok(0) => { + assert!(s.try_send(i).is_ok()); + break; + } + Ok(_) => panic!(), + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let mut done = false; + while !done { + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready_timeout(ms(100)) { + Err(_) => {} + Ok(0) => { + assert_eq!(r.try_recv(), Ok(i)); + done = true; + } + Ok(_) => panic!(), + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + let mut sel = Select::new(); + sel.send(&s); + sel.recv(&r); + assert!(sel.ready_timeout(ms(100)).is_err()); + + let (s, r) = unbounded::(); + let mut sel = Select::new(); + sel.send(&s); + sel.recv(&r); + match sel.ready_timeout(ms(100)) { + Err(_) => panic!(), + Ok(0) => assert!(s.try_send(0).is_ok()), + Ok(_) => panic!(), + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 1..4 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + { + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => assert!(s.try_send(new_r).is_ok()), + _ => panic!(), + } + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + let new = { + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => r + .try_recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap(), + _ => panic!(), + } + }; + r = new; + } + }); + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let hits = vec![Cell::new(0usize); 4]; + for _ in 0..COUNT { + let after = after(ms(0)); + let tick = tick(ms(0)); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&after); + sel.recv(&tick); + match sel.ready() { + 0 => { + r1.try_recv().unwrap(); + hits[0].set(hits[0].get() + 1); + } + 1 => { + r2.try_recv().unwrap(); + hits[1].set(hits[1].get() + 1); + } + 2 => { + after.try_recv().unwrap(); + hits[2].set(hits[2].get() + 1); + } + 3 => { + tick.try_recv().unwrap(); + hits[3].set(hits[3].get() + 1); + } + _ => panic!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 100_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + let mut sel = Select::new(); + let mut oper1 = None; + let mut oper2 = None; + if s1.is_empty() { + oper1 = Some(sel.send(&s1)); + } + if s2.is_empty() { + oper2 = Some(sel.send(&s2)); + } + let oper3 = sel.send(&s3); + let oper = sel.select(); + match oper.index() { + i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), + i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), + i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), + _ => unreachable!(), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&r3); + loop { + match sel.ready() { + 0 => { + if r1.try_recv().is_ok() { + hits[0].set(hits[0].get() + 1); + break; + } + } + 1 => { + if r2.try_recv().is_ok() { + hits[1].set(hits[1].get() + 1); + break; + } + } + 2 => { + if r3.try_recv().is_ok() { + hits[2].set(hits[2].get() + 1); + break; + } + } + _ => unreachable!(), + } + } + } + assert!(hits.iter().all(|x| x.get() > 0)); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/same_channel.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/same_channel.rs new file mode 100644 index 0000000..da4c8f3 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/same_channel.rs @@ -0,0 +1,112 @@ +use std::time::Duration; + +use crossbeam_channel::{after, bounded, never, tick, unbounded}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn after_same_channel() { + let r = after(ms(50)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let r3 = after(ms(50)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); + + let r4 = after(ms(100)); + assert!(!r.same_channel(&r4)); + assert!(!r2.same_channel(&r4)); +} + +#[test] +fn array_same_channel() { + let (s, r) = bounded::(1); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = bounded::(1); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn list_same_channel() { + let (s, r) = unbounded::(); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = unbounded::(); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn never_same_channel() { + let r = never::(); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + // Never channel are always equal to one another. + let r3 = never::(); + assert!(r.same_channel(&r3)); + assert!(r2.same_channel(&r3)); +} + +#[test] +fn tick_same_channel() { + let r = tick(ms(50)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let r3 = tick(ms(50)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); + + let r4 = tick(ms(100)); + assert!(!r.same_channel(&r4)); + assert!(!r2.same_channel(&r4)); +} + +#[test] +fn zero_same_channel() { + let (s, r) = bounded::(0); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = bounded::(0); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn different_flavors_same_channel() { + let (s1, r1) = bounded::(0); + let (s2, r2) = unbounded::(); + + assert!(!s1.same_channel(&s2)); + assert!(!r1.same_channel(&r2)); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/select.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/select.rs new file mode 100644 index 0000000..4cf08b6 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/select.rs @@ -0,0 +1,1301 @@ +//! Tests for channel selection using the `Select` struct. + +use std::any::Any; +use std::cell::Cell; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, tick, unbounded, Receiver, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => panic!(), + _ => unreachable!(), + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + } +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&r3); + let oper4 = sel.recv(&r4); + let oper5 = sel.recv(&r5); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => panic!(), + i if i == oper3 => panic!(), + i if i == oper4 => panic!(), + i if i == oper5 => assert_eq!(oper.recv(&r5), Ok(5)), + _ => unreachable!(), + } +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + r2.recv().unwrap(); + }) + .unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r2).is_err()), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + let mut sel = Select::new(); + let _oper1 = sel.recv(&r1); + let _oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } + + drop(s1); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + + let mut sel = Select::new(); + let _oper1 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } + + let mut sel = Select::new(); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + let mut sel = Select::new(); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + } + Ok(_) => unreachable!(), + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.send(&s, 0).is_err()), + _ => unreachable!(), + }, + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.send(&s, 0).is_err()), + _ => unreachable!(), + }, + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + + let mut sel = Select::new(); + let oper = sel.try_select(); + assert!(oper.is_err()); + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + let mut sel = Select::new(); + let oper = sel.select_timeout(ms(500)); + assert!(oper.is_err()); + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => oper.send(&s1, 1).unwrap(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => oper.send(&s2, 2).unwrap(), + _ => unreachable!(), + } + } + }) + .unwrap(); +} + +#[test] +fn loop_try() { + const RUNS: usize = 20; + + for _ in 0..RUNS { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + let (s_end, r_end) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| loop { + let mut done = false; + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.send(&s1, 1); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + + let mut sel = Select::new(); + let oper1 = sel.recv(&r_end); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.recv(&r_end); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + }); + + scope.spawn(|_| loop { + if let Ok(x) = r2.try_recv() { + assert_eq!(x, 2); + break; + } + + let mut done = false; + let mut sel = Select::new(); + let oper1 = sel.recv(&r_end); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.recv(&r_end); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => assert!(oper.send(&s2, 2).is_ok()), + _ => unreachable!(), + }, + } + + drop(s_end); + }); + }) + .unwrap(); + } +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert!(r3.try_recv().is_err()); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => drop(oper.recv(&r1)), + i if i == oper2 => drop(oper.recv(&r2)), + _ => unreachable!(), + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => drop(oper.recv(&r2)), + _ => unreachable!(), + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => drop(oper.recv(&r)), + _ => unreachable!(), + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r), Ok(())), + _ => unreachable!(), + } + + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let hit = vec![Cell::new(false); 4]; + + while hit.iter().map(|h| h.get()).any(|hit| !hit) { + let mut sel = Select::new(); + let oper0 = sel.recv(&r); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper3 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper0 => { + assert!(oper.recv(&r).is_ok()); + hit[0].set(true); + } + i if i == oper1 => { + assert!(oper.recv(&r).is_ok()); + hit[1].set(true); + } + i if i == oper2 => { + assert!(oper.send(&s, 0).is_ok()); + hit[2].set(true); + } + i if i == oper3 => { + assert!(oper.send(&s, 0).is_ok()); + hit[3].set(true); + } + _ => unreachable!(), + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert!(oper.send(&s, 0).is_ok()); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert_eq!(oper.recv(&r), Ok(0)); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert!(oper.send(&s, 1).is_ok()); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert_eq!(oper.recv(&r), Ok(1)); + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert_eq!(oper.recv(&r2), Ok(i)), + _ => unreachable!(), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s1, i).is_ok()), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let done = false; + while !done { + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => { + assert!(oper.send(&s, i).is_ok()); + break; + } + _ => unreachable!(), + }, + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let mut done = false; + while !done { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => { + assert_eq!(oper.recv(&r), Ok(i)); + done = true; + } + _ => unreachable!(), + }, + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper2 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => panic!(), + ix if ix == oper2 => panic!(), + _ => unreachable!(), + }, + } + + let (s, r) = unbounded::(); + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper2 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s, 0).is_ok()), + ix if ix == oper2 => panic!(), + _ => unreachable!(), + }, + } +} + +#[test] +fn matching() { + const THREADS: usize = 44; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn matching_with_leftover() { + const THREADS: usize = 55; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + s.send(!0).unwrap(); + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 0..3 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + { + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s, new_r).is_ok()), + _ => unreachable!(), + } + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + let new = { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => oper + .recv(&r) + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap(), + _ => unreachable!(), + } + }; + r = new; + } + }); + }) + .unwrap(); + } +} + +#[test] +fn linearizable_try() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => unreachable!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), + ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), + _ => unreachable!(), + }, + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn linearizable_timeout() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(0)); + match oper { + Err(_) => unreachable!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), + ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), + _ => unreachable!(), + }, + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let hits = vec![Cell::new(0usize); 4]; + for _ in 0..COUNT { + let after = after(ms(0)); + let tick = tick(ms(0)); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&after); + let oper4 = sel.recv(&tick); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits[0].set(hits[0].get() + 1); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits[1].set(hits[1].get() + 1); + } + i if i == oper3 => { + oper.recv(&after).unwrap(); + hits[2].set(hits[2].get() + 1); + } + i if i == oper4 => { + oper.recv(&tick).unwrap(); + hits[3].set(hits[3].get() + 1); + } + _ => unreachable!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + let mut sel = Select::new(); + let mut oper1 = None; + let mut oper2 = None; + if s1.is_empty() { + oper1 = Some(sel.send(&s1)); + } + if s2.is_empty() { + oper2 = Some(sel.send(&s2)); + } + let oper3 = sel.send(&s3); + let oper = sel.select(); + match oper.index() { + i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), + i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), + i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), + _ => unreachable!(), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&r3); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits[0].set(hits[0].get() + 1); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits[1].set(hits[1].get() + 1); + } + i if i == oper3 => { + oper.recv(&r3).unwrap(); + hits[2].set(hits[2].get() + 1); + } + _ => unreachable!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); + }) + .unwrap(); +} + +#[test] +fn sync_and_clone() { + const THREADS: usize = 20; + + let (s, r) = &bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let sel = &sel; + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = sel.clone(); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn send_and_clone() { + const THREADS: usize = 20; + + let (s, r) = &bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + + scope(|scope| { + for i in 0..THREADS { + let mut sel = sel.clone(); + scope.spawn(move |_| { + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn reuse() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + + for i in 0..COUNT { + for _ in 0..2 { + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/select_macro.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/select_macro.rs new file mode 100644 index 0000000..c05f7a0 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/select_macro.rs @@ -0,0 +1,1436 @@ +//! Tests for the `select!` macro. + +#![forbid(unsafe_code)] // select! is safe. + +use std::any::Any; +use std::cell::Cell; +use std::ops::Deref; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, never, select, tick, unbounded}; +use crossbeam_channel::{Receiver, RecvError, SendError, Sender, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + recv(r2) -> _ => panic!(), + } + + s2.send(2).unwrap(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + } +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + recv(r3) -> _ => panic!(), + recv(r4) -> _ => panic!(), + recv(r5) -> v => assert_eq!(v, Ok(5)), + } +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + + r2.recv().unwrap(); + }) + .unwrap(); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + select! { + recv(r2) -> v => assert!(v.is_err()), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + default => {} + } + + drop(s1); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default => panic!(), + } + + s2.send(2).unwrap(); + + select! { + recv(r2) -> v => assert_eq!(v, Ok(2)), + default => panic!(), + } + + select! { + recv(r2) -> _ => panic!(), + default => {}, + } + + select! { + default => {}, + } +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + default(ms(1000)) => {}, + } + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + select! { + default(ms(1000)) => { + select! { + recv(r) -> v => assert!(v.is_err()), + default => panic!(), + } + } + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + select! { + recv(r) -> res => assert!(res.is_err()), + default => panic!(), + } + + let (_, r) = unbounded::(); + + select! { + recv(r) -> res => assert!(res.is_err()), + default(ms(1000)) => panic!(), + } + + let (s, _) = bounded::(0); + + select! { + send(s, 0) -> res => assert!(res.is_err()), + default => panic!(), + } + + let (s, _) = bounded::(0); + + select! { + send(s, 0) -> res => assert!(res.is_err()), + default(ms(1000)) => panic!(), + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + select! { + default => {} + } + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + select! { + default(ms(500)) => {} + } + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + select! { + send(s1, 1) -> _ => {}, + send(s2, 2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + send(s2, 2) -> _ => {}, + } + } + }) + .unwrap(); +} + +#[test] +fn loop_try() { + const RUNS: usize = 20; + + for _ in 0..RUNS { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + let (s_end, r_end) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| loop { + select! { + send(s1, 1) -> _ => break, + default => {} + } + + select! { + recv(r_end) -> _ => break, + default => {} + } + }); + + scope.spawn(|_| loop { + if let Ok(x) = r2.try_recv() { + assert_eq!(x, 2); + break; + } + + select! { + recv(r_end) -> _ => break, + default => {} + } + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + send(s2, 2) -> _ => {}, + default(ms(500)) => panic!(), + } + + drop(s_end); + }); + }) + .unwrap(); + } +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert_eq!(r3.try_recv(), Err(TryRecvError::Empty)); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + select! { + recv(r1) -> _ => {}, + recv(r2) -> _ => {}, + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => {}, + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + select! { + recv(r) -> _ => {} + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + select! { + recv(r) -> v => assert!(v.is_ok()), + } + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + select! { + recv(r) -> v => assert!(v.is_err()) + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let mut hit = [false; 4]; + + while hit.iter().any(|hit| !hit) { + select! { + recv(r) -> _ => hit[0] = true, + recv(r) -> _ => hit[1] = true, + send(s, 0) -> _ => hit[2] = true, + send(s, 0) -> _ => hit[3] = true, + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + select! { + send(s, 0) -> _ => { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(0)); + select! { + send(s, 1) -> _ => { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(1)); + } + } + } + } + } + } + } + } +} + +#[test] +#[should_panic(expected = "send panicked")] +fn panic_sender() { + fn get() -> Sender { + panic!("send panicked") + } + + #[allow(unreachable_code)] + { + select! { + send(get(), panic!()) -> _ => {} + } + } +} + +#[test] +#[should_panic(expected = "recv panicked")] +fn panic_receiver() { + fn get() -> Receiver { + panic!("recv panicked") + } + + select! { + recv(get()) -> _ => {} + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(i)), + recv(r2) -> v => assert_eq!(v, Ok(i)), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + send(s1, i) -> _ => {}, + send(s2, i) -> _ => {}, + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(i)), + send(s2, i) -> _ => {}, + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + loop { + select! { + send(s, i) -> _ => break, + default(ms(100)) => {} + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + loop { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(i)); + break; + } + default(ms(100)) => {} + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + select! { + send(s, 0) -> _ => panic!(), + recv(r) -> _ => panic!(), + default(ms(500)) => {} + } + + let (s, r) = unbounded::(); + select! { + send(s, 0) -> _ => {}, + recv(r) -> _ => panic!(), + default(ms(500)) => panic!(), + } +} + +#[test] +fn matching() { + const THREADS: usize = 44; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_ne!(v.unwrap(), i), + send(s, i) -> _ => {}, + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn matching_with_leftover() { + const THREADS: usize = 55; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_ne!(v.unwrap(), i), + send(s, i) -> _ => {}, + } + }); + } + s.send(!0).unwrap(); + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 0..3 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + select! { + send(s, new_r) -> _ => {} + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = select! { + recv(r) -> msg => { + msg.unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + } + } + }); + }) + .unwrap(); + } +} + +#[test] +fn linearizable_default() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + default => unreachable!() + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn linearizable_timeout() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + default(ms(0)) => unreachable!() + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 4]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + recv(after(ms(0))) -> _ => hits[2] += 1, + recv(tick(ms(0))) -> _ => hits[3] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let (hole, _r) = bounded(0); + + for _ in 0..COUNT { + let s1 = if s1.is_empty() { &s1 } else { &hole }; + let s2 = if s2.is_empty() { &s2 } else { &hole }; + + select! { + send(s1, ()) -> res => assert!(res.is_ok()), + send(s2, ()) -> res => assert!(res.is_ok()), + send(s3, ()) -> res => assert!(res.is_ok()), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0].set(hits[0].get() + 1), + recv(r2) -> _ => hits[1].set(hits[1].get() + 1), + recv(r3) -> _ => hits[2].set(hits[2].get() + 1), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); + }) + .unwrap(); +} + +#[test] +fn fairness_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + while hits[0] + hits[1] < COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / 4)); +} + +#[test] +fn fairness_send() { + const COUNT: usize = 10_000; + + let (s1, _r1) = bounded::<()>(COUNT); + let (s2, _r2) = unbounded::<()>(); + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + send(s1, ()) -> _ => hits[0] += 1, + send(s2, ()) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / 4)); +} + +#[test] +fn references() { + let (s, r) = unbounded::(); + select! { + send(s, 0) -> _ => {} + recv(r) -> _ => {} + } + select! { + send(&&&&s, 0) -> _ => {} + recv(&&&&r) -> _ => {} + } + select! { + recv(Some(&r).unwrap_or(&never())) -> _ => {}, + default => {} + } + select! { + recv(Some(r).unwrap_or(never())) -> _ => {}, + default => {} + } +} + +#[test] +fn case_blocks() { + let (s, r) = unbounded::(); + + select! { + recv(r) -> _ => 3.0, + recv(r) -> _ => loop { + unreachable!() + }, + recv(r) -> _ => match 7 + 3 { + _ => unreachable!() + }, + default => 7. + }; + + select! { + recv(r) -> msg => if msg.is_ok() { + unreachable!() + }, + default => () + } + + drop(s); +} + +#[test] +fn move_handles() { + let (s, r) = unbounded::(); + select! { + recv((move || r)()) -> _ => {} + send((move || s)(), 0) -> _ => {} + } +} + +#[test] +fn infer_types() { + let (s, r) = unbounded(); + select! { + recv(r) -> _ => {} + default => {} + } + s.send(()).unwrap(); + + let (s, r) = unbounded(); + select! { + send(s, ()) -> _ => {} + } + r.recv().unwrap(); +} + +#[test] +fn default_syntax() { + let (s, r) = bounded::(0); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + select! { + send(s, 0) -> _ => panic!(), + default() => {} + } + select! { + default => {} + } + select! { + default() => {} + } +} + +#[test] +fn same_variable_name() { + let (_, r) = unbounded::(); + select! { + recv(r) -> r => assert!(r.is_err()), + } +} + +#[test] +fn handles_on_heap() { + let (s, r) = unbounded::(); + let (s, r) = (Box::new(s), Box::new(r)); + + select! { + send(*s, 0) -> _ => {} + recv(*r) -> _ => {} + default => {} + } + + drop(s); + drop(r); +} + +#[test] +fn once_blocks() { + let (s, r) = unbounded::(); + + let once = Box::new(()); + select! { + send(s, 0) -> _ => drop(once), + } + + let once = Box::new(()); + select! { + recv(r) -> _ => drop(once), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + send(s, 0) -> _ => drop(once1), + default => drop(once2), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + recv(r) -> _ => drop(once1), + default => drop(once2), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + recv(r) -> _ => drop(once1), + send(s, 0) -> _ => drop(once2), + } +} + +#[test] +fn once_receiver() { + let (_, r) = unbounded::(); + + let once = Box::new(()); + let get = move || { + drop(once); + r + }; + + select! { + recv(get()) -> _ => {} + } +} + +#[test] +fn once_sender() { + let (s, _) = unbounded::(); + + let once = Box::new(()); + let get = move || { + drop(once); + s + }; + + select! { + send(get(), 5) -> _ => {} + } +} + +#[test] +fn parse_nesting() { + let (_, r) = unbounded::(); + + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + default => {} + } + } + } + } + } + } + } +} + +#[test] +fn evaluate() { + let (s, r) = unbounded::(); + + let v = select! { + recv(r) -> _ => "foo".into(), + send(s, 0) -> _ => "bar".to_owned(), + default => "baz".to_string(), + }; + assert_eq!(v, "bar"); + + let v = select! { + recv(r) -> _ => "foo".into(), + default => "baz".to_string(), + }; + assert_eq!(v, "foo"); + + let v = select! { + recv(r) -> _ => "foo".into(), + default => "baz".to_string(), + }; + assert_eq!(v, "baz"); +} + +#[test] +fn deref() { + use crossbeam_channel as cc; + + struct Sender(cc::Sender); + struct Receiver(cc::Receiver); + + impl Deref for Receiver { + type Target = cc::Receiver; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl Deref for Sender { + type Target = cc::Sender; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + let (s, r) = bounded::(0); + let (s, r) = (Sender(s), Receiver(r)); + + select! { + send(s, 0) -> _ => panic!(), + recv(r) -> _ => panic!(), + default => {} + } +} + +#[test] +fn result_types() { + let (s, _) = bounded::(0); + let (_, r) = bounded::(0); + + select! { + recv(r) -> res => drop::>(res), + } + select! { + recv(r) -> res => drop::>(res), + default => {} + } + select! { + recv(r) -> res => drop::>(res), + default(ms(0)) => {} + } + + select! { + send(s, 0) -> res => drop::>>(res), + } + select! { + send(s, 0) -> res => drop::>>(res), + default => {} + } + select! { + send(s, 0) -> res => drop::>>(res), + default(ms(0)) => {} + } + + select! { + send(s, 0) -> res => drop::>>(res), + recv(r) -> res => drop::>(res), + } +} + +#[test] +fn try_recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> _ => panic!(), + default => {} + } + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + default => panic!(), + } + thread::sleep(ms(500)); + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + default => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + select! { + send(s, 7) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + } + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(9)), + } + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + send(s, 7) -> res => res.unwrap(), + } + select! { + send(s, 8) -> res => res.unwrap(), + } + select! { + send(s, 9) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> _ => panic!(), + default(ms(1000)) => {} + } + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + default(ms(1000)) => panic!(), + } + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + default(ms(1000)) => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + send(s, 7) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> _ => panic!(), + default => {} + } + thread::sleep(ms(1500)); + select! { + send(s, 8) -> res => res.unwrap(), + default => panic!(), + } + thread::sleep(ms(500)); + select! { + send(s, 8) -> res => assert_eq!(res, Err(SendError(8))), + default => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> res => res.unwrap(), + } + thread::sleep(ms(1000)); + select! { + send(s, 8) -> res => res.unwrap(), + } + thread::sleep(ms(1000)); + select! { + send(s, 9) -> res => res.unwrap(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + } + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + select! { + recv(r) -> v => assert_eq!(v, Ok(9)), + } + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> _ => panic!(), + default(ms(1000)) => {} + } + select! { + send(s, 8) -> res => res.unwrap(), + default(ms(1000)) => panic!(), + } + select! { + send(s, 9) -> res => assert_eq!(res, Err(SendError(9))), + default(ms(1000)) => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, ()) -> res => assert_eq!(res, Err(SendError(()))), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> res => assert_eq!(res, Err(RecvError)), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/thread_locals.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/thread_locals.rs new file mode 100644 index 0000000..9e27146 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/thread_locals.rs @@ -0,0 +1,51 @@ +//! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. + +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{select, unbounded}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +#[cfg_attr(target_os = "macos", ignore = "TLS is destroyed too early on macOS")] +fn use_while_exiting() { + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + // A blocking operation after the thread-locals have been dropped. This will attempt to + // use the thread-locals and must not panic. + let (_s, r) = unbounded::<()>(); + select! { + recv(r) -> _ => {} + default(ms(100)) => {} + } + } + } + + thread_local! { + static FOO: Foo = Foo; + } + + let (s, r) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(|_| { + // First initialize `FOO`, then the thread-locals related to crossbeam-channel. + FOO.with(|_| ()); + r.recv().unwrap(); + // At thread exit, thread-locals related to crossbeam-channel get dropped first and + // `FOO` is dropped last. + }); + + scope.spawn(|_| { + thread::sleep(ms(100)); + s.send(()).unwrap(); + }); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/tick.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/tick.rs new file mode 100644 index 0000000..5dc8730 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/tick.rs @@ -0,0 +1,348 @@ +//! Tests for the tick channel flavor. + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, select, tick, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn fire() { + let start = Instant::now(); + let r = tick(ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(100)); + + let fired = r.try_recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired >= ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + + select! { + recv(r) -> _ => {} + recv(tick(ms(200))) -> _ => panic!(), + } +} + +#[test] +fn intervals() { + let start = Instant::now(); + let r = tick(ms(50)); + + let t1 = r.recv().unwrap(); + assert!(start + ms(50) <= t1); + assert!(start + ms(100) > t1); + + thread::sleep(ms(300)); + let t2 = r.try_recv().unwrap(); + assert!(start + ms(100) <= t2); + assert!(start + ms(150) > t2); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + let t3 = r.recv().unwrap(); + assert!(start + ms(400) <= t3); + assert!(start + ms(450) > t3); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn capacity() { + const COUNT: usize = 10; + + for i in 0..COUNT { + let r = tick(ms(i as u64)); + assert_eq!(r.capacity(), Some(1)); + } +} + +#[test] +fn len_empty_full() { + let r = tick(ms(50)); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + thread::sleep(ms(100)); + + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.try_recv().unwrap(); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let r = tick(ms(200)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv() { + let start = Instant::now(); + let r = tick(ms(50)); + + let fired = r.recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired < fired - start); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = tick(ms(200)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(200)); + assert!(fired - start <= ms(250)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(300)); + assert!(now - start <= ms(350)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(400)); + assert!(fired - start <= ms(450)); +} + +#[test] +fn recv_two() { + let r1 = tick(ms(50)); + let r2 = tick(ms(50)); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..10 { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + } + }); + scope.spawn(|_| { + for _ in 0..10 { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_race() { + select! { + recv(tick(ms(50))) -> _ => {} + recv(tick(ms(100))) -> _ => panic!(), + } + + select! { + recv(tick(ms(100))) -> _ => panic!(), + recv(tick(ms(50))) -> _ => {} + } +} + +#[test] +fn stress_default() { + const COUNT: usize = 10; + + for _ in 0..COUNT { + select! { + recv(tick(ms(0))) -> _ => {} + default => panic!(), + } + } + + for _ in 0..COUNT { + select! { + recv(tick(ms(100))) -> _ => panic!(), + default => {} + } + } +} + +#[test] +fn select() { + const THREADS: usize = 4; + + let hits = AtomicUsize::new(0); + let r1 = tick(ms(200)); + let r2 = tick(ms(300)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let timeout = after(ms(1100)); + loop { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&timeout); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + i if i == oper3 => { + oper.recv(&timeout).unwrap(); + break; + } + _ => unreachable!(), + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), 8); +} + +#[test] +fn ready() { + const THREADS: usize = 4; + + let hits = AtomicUsize::new(0); + let r1 = tick(ms(200)); + let r2 = tick(ms(300)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let timeout = after(ms(1100)); + 'outer: loop { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&timeout); + loop { + match sel.ready() { + 0 => { + if r1.try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + 1 => { + if r2.try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + 2 => { + if timeout.try_recv().is_ok() { + break 'outer; + } + } + _ => unreachable!(), + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), 8); +} + +#[test] +fn fairness() { + const COUNT: usize = 30; + + for &dur in &[0, 1] { + let mut hits = [0usize; 2]; + + for _ in 0..COUNT { + let r1 = tick(ms(dur)); + let r2 = tick(ms(dur)); + + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 30; + + for &dur in &[0, 1] { + let mut hits = [0usize; 5]; + + for _ in 0..COUNT { + let r = tick(ms(dur)); + + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} diff --git a/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/zero.rs b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/zero.rs new file mode 100644 index 0000000..66dcc1e --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-channel-0.5.0/tests/zero.rs @@ -0,0 +1,554 @@ +//! Tests for the zero channel flavor. + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, select, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = bounded(0); + assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn capacity() { + let (s, r) = bounded::<()>(0); + assert_eq!(s.capacity(), Some(0)); + assert_eq!(r.capacity(), Some(0)); +} + +#[test] +fn len_empty_full() { + let (s, r) = bounded(0); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); + + scope(|scope| { + scope.spawn(|_| s.send(0).unwrap()); + scope.spawn(|_| r.recv().unwrap()); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); +} + +#[test] +fn try_recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); + thread::sleep(ms(1500)); + assert_eq!(s.try_send(8), Ok(())); + thread::sleep(ms(500)); + assert_eq!(s.try_send(9), Err(TrySendError::Disconnected(9))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + s.send(7).unwrap(); + thread::sleep(ms(1000)); + s.send(8).unwrap(); + thread::sleep(ms(1000)); + s.send(9).unwrap(); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(7)); + assert_eq!(r.recv(), Ok(8)); + assert_eq!(r.recv(), Ok(9)); + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!( + s.send_timeout(7, ms(1000)), + Err(SendTimeoutError::Timeout(7)) + ); + assert_eq!(s.send_timeout(8, ms(1000)), Ok(())); + assert_eq!( + s.send_timeout(9, ms(1000)), + Err(SendTimeoutError::Disconnected(9)) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(8)); + }); + }) + .unwrap(); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + + let (s, r) = bounded(0); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + assert_eq!(r.len(), 0); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + assert_eq!(s.len(), 0); + } + }); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send(()), Err(SendError(()))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded::(0); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 1000; + + let (request_s, request_r) = bounded(0); + let (response_s, response_r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + let _ = request_s.try_send(()); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(()) = s.send_timeout(i, ms(10)) { + break; + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..100 { + let steps = rng.gen_range(0, 3_000); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + } +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(0); + let (s2, r2) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }); + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + send(s1, ()) -> _ => hits[0] += 1, + send(s2, ()) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }) + .unwrap(); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }); + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + send(s, ()) -> _ => hits[0] += 1, + send(s, ()) -> _ => hits[1] += 1, + send(s, ()) -> _ => hits[2] += 1, + send(s, ()) -> _ => hits[3] += 1, + send(s, ()) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }) + .unwrap(); +} + +#[test] +fn recv_in_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(100)); + r.recv() + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + s.send(()).unwrap(); + }); + + select! { + send(s, r.recv().unwrap()) -> _ => {} + } + }) + .unwrap(); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(0); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-deque-0.8.0/.cargo-checksum.json new file mode 100644 index 0000000..134b090 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"628c53b9d367911dc12f8ee4518b25e08ac01cad5e221c6d73d383bf385734a2","Cargo.toml":"d1b440a335068d27d405cf9b112ba21c680962b5da74749f58d8b3c075168783","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"c2098e8531a9e6d08f2deed557ce5ee0247f603a31b42f6200b03028c35dcf36","src/deque.rs":"1ae47adb7848c7422b98a69a705baefedcfb6d895164c6e42ce6f37d0543467d","src/lib.rs":"9a28507974a371f5dad5311f97376e41bdeb043a2058e78d1ca6b923aeb15983","tests/fifo.rs":"b5ff91efac6c35ca62d7438fb6b65127cd8eea64fcf43d317726601b3e322581","tests/injector.rs":"ac33b424cc8a99bfaa4f1d4965b536f21e7c6a2fccc9ec8c8e39bf10f563b6ab","tests/lifo.rs":"c513e13cf389482edff89d397217ff315ffb8add6819b266def28a09b5b68c36","tests/steal.rs":"cdf588cc13eeb275ef1231eb18e3245faca7a2d054fa6527bfdba2a34bc8f7bf"},"package":"94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/BUILD.bazel b/third_party/cargo/vendor/crossbeam-deque-0.8.0/BUILD.bazel new file mode 100644 index 0000000..e177c88 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/BUILD.bazel @@ -0,0 +1,68 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "crossbeam_deque", + srcs = glob(["**/*.rs"]), + crate_features = [ + "crossbeam-epoch", + "crossbeam-utils", + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.8.0", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/cfg-if-1.0.0:cfg_if", + "//third_party/cargo/vendor/crossbeam-epoch-0.9.1:crossbeam_epoch", + "//third_party/cargo/vendor/crossbeam-utils-0.8.1:crossbeam_utils", + ], +) + +# Unsupported target "fifo" with type "test" omitted + +# Unsupported target "injector" with type "test" omitted + +# Unsupported target "lifo" with type "test" omitted + +# Unsupported target "steal" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-deque-0.8.0/CHANGELOG.md new file mode 100644 index 0000000..da37edc --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/CHANGELOG.md @@ -0,0 +1,101 @@ +# Version 0.8.0 + +- Bump the minimum supported Rust version to 1.36. +- Add `Worker::len()` and `Injector::len()` methods. +- Add `std` (enabled by default) feature for forward compatibility. + +# Version 0.7.3 + +- Stop stealing from the same deque. (#448) +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) + +# Version 0.7.2 + +- Bump `crossbeam-epoch` to `0.8`. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.7.1 + +- Bump the minimum required version of `crossbeam-utils`. + +# Version 0.7.0 + +- Make `Worker::pop()` faster in the FIFO case. +- Replace `fifo()` nad `lifo()` with `Worker::new_fifo()` and `Worker::new_lifo()`. +- Add more batched steal methods. +- Introduce `Injector`, a MPMC queue. +- Rename `Steal::Data` to `Steal::Success`. +- Add `Steal::or_else()` and implement `FromIterator` for `Steal`. +- Add `#[must_use]` to `Steal`. + +# Version 0.6.3 + +- Bump `crossbeam-epoch` to `0.7`. + +# Version 0.6.2 + +- Update `crosbeam-utils` to `0.6`. + +# Version 0.6.1 + +- Change a few `Relaxed` orderings to `Release` in order to fix false positives by tsan. + +# Version 0.6.0 + +- Add `Stealer::steal_many` for batched stealing. +- Change the return type of `pop` to `Pop` so that spinning can be handled manually. + +# Version 0.5.2 + +- Update `crossbeam-utils` to `0.5.0`. + +# Version 0.5.1 + +- Minor optimizations. + +# Version 0.5.0 + +- Add two deque constructors : `fifo()` and `lifo()`. +- Update `rand` to `0.5.3`. +- Rename `Deque` to `Worker`. +- Return `Option` from `Stealer::steal`. +- Remove methods `Deque::len` and `Stealer::len`. +- Remove method `Deque::stealer`. +- Remove method `Deque::steal`. + +# Version 0.4.1 + +- Update `crossbeam-epoch` to `0.5.0`. + +# Version 0.4.0 + +- Update `crossbeam-epoch` to `0.4.2`. +- Update `crossbeam-utils` to `0.4.0`. +- Require minimum Rust version 1.25. + +# Version 0.3.1 + +- Add `Deque::capacity`. +- Add `Deque::min_capacity`. +- Add `Deque::shrink_to_fit`. +- Update `crossbeam-epoch` to `0.3.0`. +- Support Rust 1.20. +- Shrink the buffer in `Deque::push` if necessary. + +# Version 0.3.0 + +- Update `crossbeam-epoch` to `0.4.0`. +- Drop support for Rust 1.13. + +# Version 0.2.0 + +- Update `crossbeam-epoch` to `0.3.0`. +- Support Rust 1.13. + +# Version 0.1.1 + +- Update `crossbeam-epoch` to `0.2.0`. + +# Version 0.1.0 + +- First implementation of the Chase-Lev deque. diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/Cargo.toml b/third_party/cargo/vendor/crossbeam-deque-0.8.0/Cargo.toml new file mode 100644 index 0000000..dd0c2e3 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/Cargo.toml @@ -0,0 +1,43 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "crossbeam-deque" +version = "0.8.0" +authors = ["The Crossbeam Project Developers"] +description = "Concurrent work-stealing deque" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque" +documentation = "https://docs.rs/crossbeam-deque" +readme = "README.md" +keywords = ["chase-lev", "lock-free", "scheduler", "scheduling"] +categories = ["algorithms", "concurrency", "data-structures"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dependencies.cfg-if] +version = "1" + +[dependencies.crossbeam-epoch] +version = "0.9" +optional = true +default-features = false + +[dependencies.crossbeam-utils] +version = "0.8" +optional = true +default-features = false +[dev-dependencies.rand] +version = "0.7.3" + +[features] +default = ["std"] +std = ["crossbeam-epoch/std", "crossbeam-utils/std"] diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/LICENSE-APACHE b/third_party/cargo/vendor/crossbeam-deque-0.8.0/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/crossbeam-queue-0.2.2/LICENSE-APACHE rename to third_party/cargo/vendor/crossbeam-deque-0.8.0/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/LICENSE-MIT b/third_party/cargo/vendor/crossbeam-deque-0.8.0/LICENSE-MIT new file mode 100644 index 0000000..068d491 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/LICENSE-MIT @@ -0,0 +1,27 @@ +The MIT License (MIT) + +Copyright (c) 2019 The Crossbeam Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/README.md b/third_party/cargo/vendor/crossbeam-deque-0.8.0/README.md new file mode 100644 index 0000000..538aed5 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/README.md @@ -0,0 +1,46 @@ +# Crossbeam Deque + +[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( +https://github.com/crossbeam-rs/crossbeam/actions) +[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque#license) +[![Cargo](https://img.shields.io/crates/v/crossbeam-deque.svg)]( +https://crates.io/crates/crossbeam-deque) +[![Documentation](https://docs.rs/crossbeam-deque/badge.svg)]( +https://docs.rs/crossbeam-deque) +[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides work-stealing deques, which are primarily intended for +building task schedulers. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-deque = "0.7" +``` + +## Compatibility + +Crossbeam Deque supports stable Rust releases going back at least six months, +and every time the minimum supported Rust version is increased, a new minor +version is released. Currently, the minimum supported Rust version is 1.36. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/src/deque.rs b/third_party/cargo/vendor/crossbeam-deque-0.8.0/src/deque.rs new file mode 100644 index 0000000..fcd6f9f --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/src/deque.rs @@ -0,0 +1,1995 @@ +// TODO(@jeehoonkang): we mutates `batch_size` inside `for i in 0..batch_size {}`. It is difficult +// to read because we're mutating the range bound. +#![allow(clippy::mut_range_bound)] + +use std::cell::{Cell, UnsafeCell}; +use std::cmp; +use std::fmt; +use std::iter::FromIterator; +use std::marker::PhantomData; +use std::mem::{self, MaybeUninit}; +use std::ptr; +use std::sync::atomic::{self, AtomicIsize, AtomicPtr, AtomicUsize, Ordering}; +use std::sync::Arc; + +use crate::epoch::{self, Atomic, Owned}; +use crate::utils::{Backoff, CachePadded}; + +// Minimum buffer capacity. +const MIN_CAP: usize = 64; +// Maximum number of tasks that can be stolen in `steal_batch()` and `steal_batch_and_pop()`. +const MAX_BATCH: usize = 32; +// If a buffer of at least this size is retired, thread-local garbage is flushed so that it gets +// deallocated as soon as possible. +const FLUSH_THRESHOLD_BYTES: usize = 1 << 10; + +/// A buffer that holds tasks in a worker queue. +/// +/// This is just a pointer to the buffer and its length - dropping an instance of this struct will +/// *not* deallocate the buffer. +struct Buffer { + /// Pointer to the allocated memory. + ptr: *mut T, + + /// Capacity of the buffer. Always a power of two. + cap: usize, +} + +unsafe impl Send for Buffer {} + +impl Buffer { + /// Allocates a new buffer with the specified capacity. + fn alloc(cap: usize) -> Buffer { + debug_assert_eq!(cap, cap.next_power_of_two()); + + let mut v = Vec::with_capacity(cap); + let ptr = v.as_mut_ptr(); + mem::forget(v); + + Buffer { ptr, cap } + } + + /// Deallocates the buffer. + unsafe fn dealloc(self) { + drop(Vec::from_raw_parts(self.ptr, 0, self.cap)); + } + + /// Returns a pointer to the task at the specified `index`. + unsafe fn at(&self, index: isize) -> *mut T { + // `self.cap` is always a power of two. + self.ptr.offset(index & (self.cap - 1) as isize) + } + + /// Writes `task` into the specified `index`. + /// + /// This method might be concurrently called with another `read` at the same index, which is + /// technically speaking a data race and therefore UB. We should use an atomic store here, but + /// that would be more expensive and difficult to implement generically for all types `T`. + /// Hence, as a hack, we use a volatile write instead. + unsafe fn write(&self, index: isize, task: T) { + ptr::write_volatile(self.at(index), task) + } + + /// Reads a task from the specified `index`. + /// + /// This method might be concurrently called with another `write` at the same index, which is + /// technically speaking a data race and therefore UB. We should use an atomic load here, but + /// that would be more expensive and difficult to implement generically for all types `T`. + /// Hence, as a hack, we use a volatile write instead. + unsafe fn read(&self, index: isize) -> T { + ptr::read_volatile(self.at(index)) + } +} + +impl Clone for Buffer { + fn clone(&self) -> Buffer { + Buffer { + ptr: self.ptr, + cap: self.cap, + } + } +} + +impl Copy for Buffer {} + +/// Internal queue data shared between the worker and stealers. +/// +/// The implementation is based on the following work: +/// +/// 1. [Chase and Lev. Dynamic circular work-stealing deque. SPAA 2005.][chase-lev] +/// 2. [Le, Pop, Cohen, and Nardelli. Correct and efficient work-stealing for weak memory models. +/// PPoPP 2013.][weak-mem] +/// 3. [Norris and Demsky. CDSchecker: checking concurrent data structures written with C/C++ +/// atomics. OOPSLA 2013.][checker] +/// +/// [chase-lev]: https://dl.acm.org/citation.cfm?id=1073974 +/// [weak-mem]: https://dl.acm.org/citation.cfm?id=2442524 +/// [checker]: https://dl.acm.org/citation.cfm?id=2509514 +struct Inner { + /// The front index. + front: AtomicIsize, + + /// The back index. + back: AtomicIsize, + + /// The underlying buffer. + buffer: CachePadded>>, +} + +impl Drop for Inner { + fn drop(&mut self) { + // Load the back index, front index, and buffer. + let b = self.back.load(Ordering::Relaxed); + let f = self.front.load(Ordering::Relaxed); + + unsafe { + let buffer = self.buffer.load(Ordering::Relaxed, epoch::unprotected()); + + // Go through the buffer from front to back and drop all tasks in the queue. + let mut i = f; + while i != b { + buffer.deref().at(i).drop_in_place(); + i = i.wrapping_add(1); + } + + // Free the memory allocated by the buffer. + buffer.into_owned().into_box().dealloc(); + } + } +} + +/// Worker queue flavor: FIFO or LIFO. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Flavor { + /// The first-in first-out flavor. + Fifo, + + /// The last-in first-out flavor. + Lifo, +} + +/// A worker queue. +/// +/// This is a FIFO or LIFO queue that is owned by a single thread, but other threads may steal +/// tasks from it. Task schedulers typically create a single worker queue per thread. +/// +/// # Examples +/// +/// A FIFO worker: +/// +/// ``` +/// use crossbeam_deque::{Steal, Worker}; +/// +/// let w = Worker::new_fifo(); +/// let s = w.stealer(); +/// +/// w.push(1); +/// w.push(2); +/// w.push(3); +/// +/// assert_eq!(s.steal(), Steal::Success(1)); +/// assert_eq!(w.pop(), Some(2)); +/// assert_eq!(w.pop(), Some(3)); +/// ``` +/// +/// A LIFO worker: +/// +/// ``` +/// use crossbeam_deque::{Steal, Worker}; +/// +/// let w = Worker::new_lifo(); +/// let s = w.stealer(); +/// +/// w.push(1); +/// w.push(2); +/// w.push(3); +/// +/// assert_eq!(s.steal(), Steal::Success(1)); +/// assert_eq!(w.pop(), Some(3)); +/// assert_eq!(w.pop(), Some(2)); +/// ``` +pub struct Worker { + /// A reference to the inner representation of the queue. + inner: Arc>>, + + /// A copy of `inner.buffer` for quick access. + buffer: Cell>, + + /// The flavor of the queue. + flavor: Flavor, + + /// Indicates that the worker cannot be shared among threads. + _marker: PhantomData<*mut ()>, // !Send + !Sync +} + +unsafe impl Send for Worker {} + +impl Worker { + /// Creates a FIFO worker queue. + /// + /// Tasks are pushed and popped from opposite ends. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::::new_fifo(); + /// ``` + pub fn new_fifo() -> Worker { + let buffer = Buffer::alloc(MIN_CAP); + + let inner = Arc::new(CachePadded::new(Inner { + front: AtomicIsize::new(0), + back: AtomicIsize::new(0), + buffer: CachePadded::new(Atomic::new(buffer)), + })); + + Worker { + inner, + buffer: Cell::new(buffer), + flavor: Flavor::Fifo, + _marker: PhantomData, + } + } + + /// Creates a LIFO worker queue. + /// + /// Tasks are pushed and popped from the same end. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::::new_lifo(); + /// ``` + pub fn new_lifo() -> Worker { + let buffer = Buffer::alloc(MIN_CAP); + + let inner = Arc::new(CachePadded::new(Inner { + front: AtomicIsize::new(0), + back: AtomicIsize::new(0), + buffer: CachePadded::new(Atomic::new(buffer)), + })); + + Worker { + inner, + buffer: Cell::new(buffer), + flavor: Flavor::Lifo, + _marker: PhantomData, + } + } + + /// Creates a stealer for this queue. + /// + /// The returned stealer can be shared among threads and cloned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::::new_lifo(); + /// let s = w.stealer(); + /// ``` + pub fn stealer(&self) -> Stealer { + Stealer { + inner: self.inner.clone(), + flavor: self.flavor, + } + } + + /// Resizes the internal buffer to the new capacity of `new_cap`. + #[cold] + unsafe fn resize(&self, new_cap: usize) { + // Load the back index, front index, and buffer. + let b = self.inner.back.load(Ordering::Relaxed); + let f = self.inner.front.load(Ordering::Relaxed); + let buffer = self.buffer.get(); + + // Allocate a new buffer and copy data from the old buffer to the new one. + let new = Buffer::alloc(new_cap); + let mut i = f; + while i != b { + ptr::copy_nonoverlapping(buffer.at(i), new.at(i), 1); + i = i.wrapping_add(1); + } + + let guard = &epoch::pin(); + + // Replace the old buffer with the new one. + self.buffer.replace(new); + let old = + self.inner + .buffer + .swap(Owned::new(new).into_shared(guard), Ordering::Release, guard); + + // Destroy the old buffer later. + guard.defer_unchecked(move || old.into_owned().into_box().dealloc()); + + // If the buffer is very large, then flush the thread-local garbage in order to deallocate + // it as soon as possible. + if mem::size_of::() * new_cap >= FLUSH_THRESHOLD_BYTES { + guard.flush(); + } + } + + /// Reserves enough capacity so that `reserve_cap` tasks can be pushed without growing the + /// buffer. + fn reserve(&self, reserve_cap: usize) { + if reserve_cap > 0 { + // Compute the current length. + let b = self.inner.back.load(Ordering::Relaxed); + let f = self.inner.front.load(Ordering::SeqCst); + let len = b.wrapping_sub(f) as usize; + + // The current capacity. + let cap = self.buffer.get().cap; + + // Is there enough capacity to push `reserve_cap` tasks? + if cap - len < reserve_cap { + // Keep doubling the capacity as much as is needed. + let mut new_cap = cap * 2; + while new_cap - len < reserve_cap { + new_cap *= 2; + } + + // Resize the buffer. + unsafe { + self.resize(new_cap); + } + } + } + } + + /// Returns `true` if the queue is empty. + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::new_lifo(); + /// + /// assert!(w.is_empty()); + /// w.push(1); + /// assert!(!w.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + let b = self.inner.back.load(Ordering::Relaxed); + let f = self.inner.front.load(Ordering::SeqCst); + b.wrapping_sub(f) <= 0 + } + + /// Returns the number of tasks in the deque. + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::new_lifo(); + /// + /// assert_eq!(w.len(), 0); + /// w.push(1); + /// assert_eq!(w.len(), 1); + /// w.push(1); + /// assert_eq!(w.len(), 2); + /// ``` + pub fn len(&self) -> usize { + let b = self.inner.back.load(Ordering::Relaxed); + let f = self.inner.front.load(Ordering::SeqCst); + b.wrapping_sub(f).max(0) as usize + } + + /// Pushes a task into the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::new_lifo(); + /// w.push(1); + /// w.push(2); + /// ``` + pub fn push(&self, task: T) { + // Load the back index, front index, and buffer. + let b = self.inner.back.load(Ordering::Relaxed); + let f = self.inner.front.load(Ordering::Acquire); + let mut buffer = self.buffer.get(); + + // Calculate the length of the queue. + let len = b.wrapping_sub(f); + + // Is the queue full? + if len >= buffer.cap as isize { + // Yes. Grow the underlying buffer. + unsafe { + self.resize(2 * buffer.cap); + } + buffer = self.buffer.get(); + } + + // Write `task` into the slot. + unsafe { + buffer.write(b, task); + } + + atomic::fence(Ordering::Release); + + // Increment the back index. + // + // This ordering could be `Relaxed`, but then thread sanitizer would falsely report data + // races because it doesn't understand fences. + self.inner.back.store(b.wrapping_add(1), Ordering::Release); + } + + /// Pops a task from the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::new_fifo(); + /// w.push(1); + /// w.push(2); + /// + /// assert_eq!(w.pop(), Some(1)); + /// assert_eq!(w.pop(), Some(2)); + /// assert_eq!(w.pop(), None); + /// ``` + pub fn pop(&self) -> Option { + // Load the back and front index. + let b = self.inner.back.load(Ordering::Relaxed); + let f = self.inner.front.load(Ordering::Relaxed); + + // Calculate the length of the queue. + let len = b.wrapping_sub(f); + + // Is the queue empty? + if len <= 0 { + return None; + } + + match self.flavor { + // Pop from the front of the queue. + Flavor::Fifo => { + // Try incrementing the front index to pop the task. + let f = self.inner.front.fetch_add(1, Ordering::SeqCst); + let new_f = f.wrapping_add(1); + + if b.wrapping_sub(new_f) < 0 { + self.inner.front.store(f, Ordering::Relaxed); + return None; + } + + unsafe { + // Read the popped task. + let buffer = self.buffer.get(); + let task = buffer.read(f); + + // Shrink the buffer if `len - 1` is less than one fourth of the capacity. + if buffer.cap > MIN_CAP && len <= buffer.cap as isize / 4 { + self.resize(buffer.cap / 2); + } + + Some(task) + } + } + + // Pop from the back of the queue. + Flavor::Lifo => { + // Decrement the back index. + let b = b.wrapping_sub(1); + self.inner.back.store(b, Ordering::Relaxed); + + atomic::fence(Ordering::SeqCst); + + // Load the front index. + let f = self.inner.front.load(Ordering::Relaxed); + + // Compute the length after the back index was decremented. + let len = b.wrapping_sub(f); + + if len < 0 { + // The queue is empty. Restore the back index to the original task. + self.inner.back.store(b.wrapping_add(1), Ordering::Relaxed); + None + } else { + // Read the task to be popped. + let buffer = self.buffer.get(); + let mut task = unsafe { Some(buffer.read(b)) }; + + // Are we popping the last task from the queue? + if len == 0 { + // Try incrementing the front index. + if self + .inner + .front + .compare_exchange( + f, + f.wrapping_add(1), + Ordering::SeqCst, + Ordering::Relaxed, + ) + .is_err() + { + // Failed. We didn't pop anything. + mem::forget(task.take()); + } + + // Restore the back index to the original task. + self.inner.back.store(b.wrapping_add(1), Ordering::Relaxed); + } else { + // Shrink the buffer if `len` is less than one fourth of the capacity. + if buffer.cap > MIN_CAP && len < buffer.cap as isize / 4 { + unsafe { + self.resize(buffer.cap / 2); + } + } + } + + task + } + } + } + } +} + +impl fmt::Debug for Worker { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Worker { .. }") + } +} + +/// A stealer handle of a worker queue. +/// +/// Stealers can be shared among threads. +/// +/// Task schedulers typically have a single worker queue per worker thread. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_deque::{Steal, Worker}; +/// +/// let w = Worker::new_lifo(); +/// w.push(1); +/// w.push(2); +/// +/// let s = w.stealer(); +/// assert_eq!(s.steal(), Steal::Success(1)); +/// assert_eq!(s.steal(), Steal::Success(2)); +/// assert_eq!(s.steal(), Steal::Empty); +/// ``` +pub struct Stealer { + /// A reference to the inner representation of the queue. + inner: Arc>>, + + /// The flavor of the queue. + flavor: Flavor, +} + +unsafe impl Send for Stealer {} +unsafe impl Sync for Stealer {} + +impl Stealer { + /// Returns `true` if the queue is empty. + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w = Worker::new_lifo(); + /// let s = w.stealer(); + /// + /// assert!(s.is_empty()); + /// w.push(1); + /// assert!(!s.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + let f = self.inner.front.load(Ordering::Acquire); + atomic::fence(Ordering::SeqCst); + let b = self.inner.back.load(Ordering::Acquire); + b.wrapping_sub(f) <= 0 + } + + /// Steals a task from the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::{Steal, Worker}; + /// + /// let w = Worker::new_lifo(); + /// w.push(1); + /// w.push(2); + /// + /// let s = w.stealer(); + /// assert_eq!(s.steal(), Steal::Success(1)); + /// assert_eq!(s.steal(), Steal::Success(2)); + /// ``` + pub fn steal(&self) -> Steal { + // Load the front index. + let f = self.inner.front.load(Ordering::Acquire); + + // A SeqCst fence is needed here. + // + // If the current thread is already pinned (reentrantly), we must manually issue the + // fence. Otherwise, the following pinning will issue the fence anyway, so we don't + // have to. + if epoch::is_pinned() { + atomic::fence(Ordering::SeqCst); + } + + let guard = &epoch::pin(); + + // Load the back index. + let b = self.inner.back.load(Ordering::Acquire); + + // Is the queue empty? + if b.wrapping_sub(f) <= 0 { + return Steal::Empty; + } + + // Load the buffer and read the task at the front. + let buffer = self.inner.buffer.load(Ordering::Acquire, guard); + let task = unsafe { buffer.deref().read(f) }; + + // Try incrementing the front index to steal the task. + if self + .inner + .front + .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed) + .is_err() + { + // We didn't steal this task, forget it. + mem::forget(task); + return Steal::Retry; + } + + // Return the stolen task. + Steal::Success(task) + } + + /// Steals a batch of tasks and pushes them into another worker. + /// + /// How many tasks exactly will be stolen is not specified. That said, this method will try to + /// steal around half of the tasks in the queue, but also not more than some constant limit. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Worker; + /// + /// let w1 = Worker::new_fifo(); + /// w1.push(1); + /// w1.push(2); + /// w1.push(3); + /// w1.push(4); + /// + /// let s = w1.stealer(); + /// let w2 = Worker::new_fifo(); + /// + /// let _ = s.steal_batch(&w2); + /// assert_eq!(w2.pop(), Some(1)); + /// assert_eq!(w2.pop(), Some(2)); + /// ``` + pub fn steal_batch(&self, dest: &Worker) -> Steal<()> { + if Arc::ptr_eq(&self.inner, &dest.inner) { + if dest.is_empty() { + return Steal::Empty; + } else { + return Steal::Success(()); + } + } + + // Load the front index. + let mut f = self.inner.front.load(Ordering::Acquire); + + // A SeqCst fence is needed here. + // + // If the current thread is already pinned (reentrantly), we must manually issue the + // fence. Otherwise, the following pinning will issue the fence anyway, so we don't + // have to. + if epoch::is_pinned() { + atomic::fence(Ordering::SeqCst); + } + + let guard = &epoch::pin(); + + // Load the back index. + let b = self.inner.back.load(Ordering::Acquire); + + // Is the queue empty? + let len = b.wrapping_sub(f); + if len <= 0 { + return Steal::Empty; + } + + // Reserve capacity for the stolen batch. + let batch_size = cmp::min((len as usize + 1) / 2, MAX_BATCH); + dest.reserve(batch_size); + let mut batch_size = batch_size as isize; + + // Get the destination buffer and back index. + let dest_buffer = dest.buffer.get(); + let mut dest_b = dest.inner.back.load(Ordering::Relaxed); + + // Load the buffer. + let buffer = self.inner.buffer.load(Ordering::Acquire, guard); + + match self.flavor { + // Steal a batch of tasks from the front at once. + Flavor::Fifo => { + // Copy the batch from the source to the destination buffer. + match dest.flavor { + Flavor::Fifo => { + for i in 0..batch_size { + unsafe { + let task = buffer.deref().read(f.wrapping_add(i)); + dest_buffer.write(dest_b.wrapping_add(i), task); + } + } + } + Flavor::Lifo => { + for i in 0..batch_size { + unsafe { + let task = buffer.deref().read(f.wrapping_add(i)); + dest_buffer.write(dest_b.wrapping_add(batch_size - 1 - i), task); + } + } + } + } + + // Try incrementing the front index to steal the batch. + if self + .inner + .front + .compare_exchange( + f, + f.wrapping_add(batch_size), + Ordering::SeqCst, + Ordering::Relaxed, + ) + .is_err() + { + return Steal::Retry; + } + + dest_b = dest_b.wrapping_add(batch_size); + } + + // Steal a batch of tasks from the front one by one. + Flavor::Lifo => { + for i in 0..batch_size { + // If this is not the first steal, check whether the queue is empty. + if i > 0 { + // We've already got the current front index. Now execute the fence to + // synchronize with other threads. + atomic::fence(Ordering::SeqCst); + + // Load the back index. + let b = self.inner.back.load(Ordering::Acquire); + + // Is the queue empty? + if b.wrapping_sub(f) <= 0 { + batch_size = i; + break; + } + } + + // Read the task at the front. + let task = unsafe { buffer.deref().read(f) }; + + // Try incrementing the front index to steal the task. + if self + .inner + .front + .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed) + .is_err() + { + // We didn't steal this task, forget it and break from the loop. + mem::forget(task); + batch_size = i; + break; + } + + // Write the stolen task into the destination buffer. + unsafe { + dest_buffer.write(dest_b, task); + } + + // Move the source front index and the destination back index one step forward. + f = f.wrapping_add(1); + dest_b = dest_b.wrapping_add(1); + } + + // If we didn't steal anything, the operation needs to be retried. + if batch_size == 0 { + return Steal::Retry; + } + + // If stealing into a FIFO queue, stolen tasks need to be reversed. + if dest.flavor == Flavor::Fifo { + for i in 0..batch_size / 2 { + unsafe { + let i1 = dest_b.wrapping_sub(batch_size - i); + let i2 = dest_b.wrapping_sub(i + 1); + let t1 = dest_buffer.read(i1); + let t2 = dest_buffer.read(i2); + dest_buffer.write(i1, t2); + dest_buffer.write(i2, t1); + } + } + } + } + } + + atomic::fence(Ordering::Release); + + // Update the back index in the destination queue. + // + // This ordering could be `Relaxed`, but then thread sanitizer would falsely report data + // races because it doesn't understand fences. + dest.inner.back.store(dest_b, Ordering::Release); + + // Return with success. + Steal::Success(()) + } + + /// Steals a batch of tasks, pushes them into another worker, and pops a task from that worker. + /// + /// How many tasks exactly will be stolen is not specified. That said, this method will try to + /// steal around half of the tasks in the queue, but also not more than some constant limit. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::{Steal, Worker}; + /// + /// let w1 = Worker::new_fifo(); + /// w1.push(1); + /// w1.push(2); + /// w1.push(3); + /// w1.push(4); + /// + /// let s = w1.stealer(); + /// let w2 = Worker::new_fifo(); + /// + /// assert_eq!(s.steal_batch_and_pop(&w2), Steal::Success(1)); + /// assert_eq!(w2.pop(), Some(2)); + /// ``` + pub fn steal_batch_and_pop(&self, dest: &Worker) -> Steal { + if Arc::ptr_eq(&self.inner, &dest.inner) { + match dest.pop() { + None => return Steal::Empty, + Some(task) => return Steal::Success(task), + } + } + + // Load the front index. + let mut f = self.inner.front.load(Ordering::Acquire); + + // A SeqCst fence is needed here. + // + // If the current thread is already pinned (reentrantly), we must manually issue the + // fence. Otherwise, the following pinning will issue the fence anyway, so we don't + // have to. + if epoch::is_pinned() { + atomic::fence(Ordering::SeqCst); + } + + let guard = &epoch::pin(); + + // Load the back index. + let b = self.inner.back.load(Ordering::Acquire); + + // Is the queue empty? + let len = b.wrapping_sub(f); + if len <= 0 { + return Steal::Empty; + } + + // Reserve capacity for the stolen batch. + let batch_size = cmp::min((len as usize - 1) / 2, MAX_BATCH - 1); + dest.reserve(batch_size); + let mut batch_size = batch_size as isize; + + // Get the destination buffer and back index. + let dest_buffer = dest.buffer.get(); + let mut dest_b = dest.inner.back.load(Ordering::Relaxed); + + // Load the buffer + let buffer = self.inner.buffer.load(Ordering::Acquire, guard); + + // Read the task at the front. + let mut task = unsafe { buffer.deref().read(f) }; + + match self.flavor { + // Steal a batch of tasks from the front at once. + Flavor::Fifo => { + // Copy the batch from the source to the destination buffer. + match dest.flavor { + Flavor::Fifo => { + for i in 0..batch_size { + unsafe { + let task = buffer.deref().read(f.wrapping_add(i + 1)); + dest_buffer.write(dest_b.wrapping_add(i), task); + } + } + } + Flavor::Lifo => { + for i in 0..batch_size { + unsafe { + let task = buffer.deref().read(f.wrapping_add(i + 1)); + dest_buffer.write(dest_b.wrapping_add(batch_size - 1 - i), task); + } + } + } + } + + // Try incrementing the front index to steal the batch. + if self + .inner + .front + .compare_exchange( + f, + f.wrapping_add(batch_size + 1), + Ordering::SeqCst, + Ordering::Relaxed, + ) + .is_err() + { + // We didn't steal this task, forget it. + mem::forget(task); + return Steal::Retry; + } + + dest_b = dest_b.wrapping_add(batch_size); + } + + // Steal a batch of tasks from the front one by one. + Flavor::Lifo => { + // Try incrementing the front index to steal the task. + if self + .inner + .front + .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed) + .is_err() + { + // We didn't steal this task, forget it. + mem::forget(task); + return Steal::Retry; + } + + // Move the front index one step forward. + f = f.wrapping_add(1); + + // Repeat the same procedure for the batch steals. + for i in 0..batch_size { + // We've already got the current front index. Now execute the fence to + // synchronize with other threads. + atomic::fence(Ordering::SeqCst); + + // Load the back index. + let b = self.inner.back.load(Ordering::Acquire); + + // Is the queue empty? + if b.wrapping_sub(f) <= 0 { + batch_size = i; + break; + } + + // Read the task at the front. + let tmp = unsafe { buffer.deref().read(f) }; + + // Try incrementing the front index to steal the task. + if self + .inner + .front + .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed) + .is_err() + { + // We didn't steal this task, forget it and break from the loop. + mem::forget(tmp); + batch_size = i; + break; + } + + // Write the previously stolen task into the destination buffer. + unsafe { + dest_buffer.write(dest_b, mem::replace(&mut task, tmp)); + } + + // Move the source front index and the destination back index one step forward. + f = f.wrapping_add(1); + dest_b = dest_b.wrapping_add(1); + } + + // If stealing into a FIFO queue, stolen tasks need to be reversed. + if dest.flavor == Flavor::Fifo { + for i in 0..batch_size / 2 { + unsafe { + let i1 = dest_b.wrapping_sub(batch_size - i); + let i2 = dest_b.wrapping_sub(i + 1); + let t1 = dest_buffer.read(i1); + let t2 = dest_buffer.read(i2); + dest_buffer.write(i1, t2); + dest_buffer.write(i2, t1); + } + } + } + } + } + + atomic::fence(Ordering::Release); + + // Update the back index in the destination queue. + // + // This ordering could be `Relaxed`, but then thread sanitizer would falsely report data + // races because it doesn't understand fences. + dest.inner.back.store(dest_b, Ordering::Release); + + // Return with success. + Steal::Success(task) + } +} + +impl Clone for Stealer { + fn clone(&self) -> Stealer { + Stealer { + inner: self.inner.clone(), + flavor: self.flavor, + } + } +} + +impl fmt::Debug for Stealer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Stealer { .. }") + } +} + +// Bits indicating the state of a slot: +// * If a task has been written into the slot, `WRITE` is set. +// * If a task has been read from the slot, `READ` is set. +// * If the block is being destroyed, `DESTROY` is set. +const WRITE: usize = 1; +const READ: usize = 2; +const DESTROY: usize = 4; + +// Each block covers one "lap" of indices. +const LAP: usize = 64; +// The maximum number of values a block can hold. +const BLOCK_CAP: usize = LAP - 1; +// How many lower bits are reserved for metadata. +const SHIFT: usize = 1; +// Indicates that the block is not the last one. +const HAS_NEXT: usize = 1; + +/// A slot in a block. +struct Slot { + /// The task. + task: UnsafeCell>, + + /// The state of the slot. + state: AtomicUsize, +} + +impl Slot { + /// Waits until a task is written into the slot. + fn wait_write(&self) { + let backoff = Backoff::new(); + while self.state.load(Ordering::Acquire) & WRITE == 0 { + backoff.snooze(); + } + } +} + +/// A block in a linked list. +/// +/// Each block in the list can hold up to `BLOCK_CAP` values. +struct Block { + /// The next block in the linked list. + next: AtomicPtr>, + + /// Slots for values. + slots: [Slot; BLOCK_CAP], +} + +impl Block { + /// Creates an empty block that starts at `start_index`. + fn new() -> Block { + // SAFETY: This is safe because: + // [1] `Block::next` (AtomicPtr) may be safely zero initialized. + // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. + // [3] `Slot::task` (UnsafeCell) may be safely zero initialized because it + // holds a MaybeUninit. + // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. + unsafe { MaybeUninit::zeroed().assume_init() } + } + + /// Waits until the next pointer is set. + fn wait_next(&self) -> *mut Block { + let backoff = Backoff::new(); + loop { + let next = self.next.load(Ordering::Acquire); + if !next.is_null() { + return next; + } + backoff.snooze(); + } + } + + /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. + unsafe fn destroy(this: *mut Block, count: usize) { + // It is not necessary to set the `DESTROY` bit in the last slot because that slot has + // begun destruction of the block. + for i in (0..count).rev() { + let slot = (*this).slots.get_unchecked(i); + + // Mark the `DESTROY` bit if a thread is still using the slot. + if slot.state.load(Ordering::Acquire) & READ == 0 + && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 + { + // If a thread is still using the slot, it will continue destruction of the block. + return; + } + } + + // No thread is using the block, now it is safe to destroy it. + drop(Box::from_raw(this)); + } +} + +/// A position in a queue. +struct Position { + /// The index in the queue. + index: AtomicUsize, + + /// The block in the linked list. + block: AtomicPtr>, +} + +/// An injector queue. +/// +/// This is a FIFO queue that can be shared among multiple threads. Task schedulers typically have +/// a single injector queue, which is the entry point for new tasks. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_deque::{Injector, Steal}; +/// +/// let q = Injector::new(); +/// q.push(1); +/// q.push(2); +/// +/// assert_eq!(q.steal(), Steal::Success(1)); +/// assert_eq!(q.steal(), Steal::Success(2)); +/// assert_eq!(q.steal(), Steal::Empty); +/// ``` +pub struct Injector { + /// The head of the queue. + head: CachePadded>, + + /// The tail of the queue. + tail: CachePadded>, + + /// Indicates that dropping a `Injector` may drop values of type `T`. + _marker: PhantomData, +} + +unsafe impl Send for Injector {} +unsafe impl Sync for Injector {} + +impl Default for Injector { + fn default() -> Self { + let block = Box::into_raw(Box::new(Block::::new())); + Self { + head: CachePadded::new(Position { + block: AtomicPtr::new(block), + index: AtomicUsize::new(0), + }), + tail: CachePadded::new(Position { + block: AtomicPtr::new(block), + index: AtomicUsize::new(0), + }), + _marker: PhantomData, + } + } +} + +impl Injector { + /// Creates a new injector queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Injector; + /// + /// let q = Injector::::new(); + /// ``` + pub fn new() -> Injector { + Self::default() + } + + /// Pushes a task into the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Injector; + /// + /// let w = Injector::new(); + /// w.push(1); + /// w.push(2); + /// ``` + pub fn push(&self, task: T) { + let backoff = Backoff::new(); + let mut tail = self.tail.index.load(Ordering::Acquire); + let mut block = self.tail.block.load(Ordering::Acquire); + let mut next_block = None; + + loop { + // Calculate the offset of the index into the block. + let offset = (tail >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + + // If we're going to have to install the next block, allocate it in advance in order to + // make the wait for other threads as short as possible. + if offset + 1 == BLOCK_CAP && next_block.is_none() { + next_block = Some(Box::new(Block::::new())); + } + + let new_tail = tail + (1 << SHIFT); + + // Try advancing the tail forward. + match self.tail.index.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, install the next one. + if offset + 1 == BLOCK_CAP { + let next_block = Box::into_raw(next_block.unwrap()); + let next_index = new_tail.wrapping_add(1 << SHIFT); + + self.tail.block.store(next_block, Ordering::Release); + self.tail.index.store(next_index, Ordering::Release); + (*block).next.store(next_block, Ordering::Release); + } + + // Write the task into the slot. + let slot = (*block).slots.get_unchecked(offset); + slot.task.get().write(MaybeUninit::new(task)); + slot.state.fetch_or(WRITE, Ordering::Release); + + return; + }, + Err(t) => { + tail = t; + block = self.tail.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Steals a task from the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::{Injector, Steal}; + /// + /// let q = Injector::new(); + /// q.push(1); + /// q.push(2); + /// + /// assert_eq!(q.steal(), Steal::Success(1)); + /// assert_eq!(q.steal(), Steal::Success(2)); + /// assert_eq!(q.steal(), Steal::Empty); + /// ``` + pub fn steal(&self) -> Steal { + let mut head; + let mut block; + let mut offset; + + let backoff = Backoff::new(); + loop { + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + + // Calculate the offset of the index into the block. + offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + } else { + break; + } + } + + let mut new_head = head + (1 << SHIFT); + + if new_head & HAS_NEXT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the queue is empty. + if head >> SHIFT == tail >> SHIFT { + return Steal::Empty; + } + + // If head and tail are not in the same block, set `HAS_NEXT` in head. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= HAS_NEXT; + } + } + + // Try moving the head index forward. + if self + .head + .index + .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire) + .is_err() + { + return Steal::Retry; + } + + unsafe { + // If we've reached the end of the block, move to the next one. + if offset + 1 == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= HAS_NEXT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + // Read the task. + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let task = slot.task.get().read().assume_init(); + + // Destroy the block if we've reached the end, or if another thread wanted to destroy + // but couldn't because we were busy reading from the slot. + if (offset + 1 == BLOCK_CAP) || (slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0) { + Block::destroy(block, offset); + } + + Steal::Success(task) + } + } + + /// Steals a batch of tasks and pushes them into a worker. + /// + /// How many tasks exactly will be stolen is not specified. That said, this method will try to + /// steal around half of the tasks in the queue, but also not more than some constant limit. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::{Injector, Worker}; + /// + /// let q = Injector::new(); + /// q.push(1); + /// q.push(2); + /// q.push(3); + /// q.push(4); + /// + /// let w = Worker::new_fifo(); + /// let _ = q.steal_batch(&w); + /// assert_eq!(w.pop(), Some(1)); + /// assert_eq!(w.pop(), Some(2)); + /// ``` + pub fn steal_batch(&self, dest: &Worker) -> Steal<()> { + let mut head; + let mut block; + let mut offset; + + let backoff = Backoff::new(); + loop { + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + + // Calculate the offset of the index into the block. + offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + } else { + break; + } + } + + let mut new_head = head; + let advance; + + if new_head & HAS_NEXT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the queue is empty. + if head >> SHIFT == tail >> SHIFT { + return Steal::Empty; + } + + // If head and tail are not in the same block, set `HAS_NEXT` in head. Also, calculate + // the right batch size to steal. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= HAS_NEXT; + // We can steal all tasks till the end of the block. + advance = (BLOCK_CAP - offset).min(MAX_BATCH); + } else { + let len = (tail - head) >> SHIFT; + // Steal half of the available tasks. + advance = ((len + 1) / 2).min(MAX_BATCH); + } + } else { + // We can steal all tasks till the end of the block. + advance = (BLOCK_CAP - offset).min(MAX_BATCH); + } + + new_head += advance << SHIFT; + let new_offset = offset + advance; + + // Try moving the head index forward. + if self + .head + .index + .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire) + .is_err() + { + return Steal::Retry; + } + + // Reserve capacity for the stolen batch. + let batch_size = new_offset - offset; + dest.reserve(batch_size); + + // Get the destination buffer and back index. + let dest_buffer = dest.buffer.get(); + let dest_b = dest.inner.back.load(Ordering::Relaxed); + + unsafe { + // If we've reached the end of the block, move to the next one. + if new_offset == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= HAS_NEXT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + // Copy values from the injector into the destination queue. + match dest.flavor { + Flavor::Fifo => { + for i in 0..batch_size { + // Read the task. + let slot = (*block).slots.get_unchecked(offset + i); + slot.wait_write(); + let task = slot.task.get().read().assume_init(); + + // Write it into the destination queue. + dest_buffer.write(dest_b.wrapping_add(i as isize), task); + } + } + + Flavor::Lifo => { + for i in 0..batch_size { + // Read the task. + let slot = (*block).slots.get_unchecked(offset + i); + slot.wait_write(); + let task = slot.task.get().read().assume_init(); + + // Write it into the destination queue. + dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task); + } + } + } + + atomic::fence(Ordering::Release); + + // Update the back index in the destination queue. + // + // This ordering could be `Relaxed`, but then thread sanitizer would falsely report + // data races because it doesn't understand fences. + dest.inner + .back + .store(dest_b.wrapping_add(batch_size as isize), Ordering::Release); + + // Destroy the block if we've reached the end, or if another thread wanted to destroy + // but couldn't because we were busy reading from the slot. + if new_offset == BLOCK_CAP { + Block::destroy(block, offset); + } else { + for i in offset..new_offset { + let slot = (*block).slots.get_unchecked(i); + + if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset); + break; + } + } + } + + Steal::Success(()) + } + } + + /// Steals a batch of tasks, pushes them into a worker, and pops a task from that worker. + /// + /// How many tasks exactly will be stolen is not specified. That said, this method will try to + /// steal around half of the tasks in the queue, but also not more than some constant limit. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::{Injector, Steal, Worker}; + /// + /// let q = Injector::new(); + /// q.push(1); + /// q.push(2); + /// q.push(3); + /// q.push(4); + /// + /// let w = Worker::new_fifo(); + /// assert_eq!(q.steal_batch_and_pop(&w), Steal::Success(1)); + /// assert_eq!(w.pop(), Some(2)); + /// ``` + pub fn steal_batch_and_pop(&self, dest: &Worker) -> Steal { + let mut head; + let mut block; + let mut offset; + + let backoff = Backoff::new(); + loop { + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + + // Calculate the offset of the index into the block. + offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + } else { + break; + } + } + + let mut new_head = head; + let advance; + + if new_head & HAS_NEXT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the queue is empty. + if head >> SHIFT == tail >> SHIFT { + return Steal::Empty; + } + + // If head and tail are not in the same block, set `HAS_NEXT` in head. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= HAS_NEXT; + // We can steal all tasks till the end of the block. + advance = (BLOCK_CAP - offset).min(MAX_BATCH + 1); + } else { + let len = (tail - head) >> SHIFT; + // Steal half of the available tasks. + advance = ((len + 1) / 2).min(MAX_BATCH + 1); + } + } else { + // We can steal all tasks till the end of the block. + advance = (BLOCK_CAP - offset).min(MAX_BATCH + 1); + } + + new_head += advance << SHIFT; + let new_offset = offset + advance; + + // Try moving the head index forward. + if self + .head + .index + .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire) + .is_err() + { + return Steal::Retry; + } + + // Reserve capacity for the stolen batch. + let batch_size = new_offset - offset - 1; + dest.reserve(batch_size); + + // Get the destination buffer and back index. + let dest_buffer = dest.buffer.get(); + let dest_b = dest.inner.back.load(Ordering::Relaxed); + + unsafe { + // If we've reached the end of the block, move to the next one. + if new_offset == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= HAS_NEXT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + // Read the task. + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let task = slot.task.get().read().assume_init(); + + match dest.flavor { + Flavor::Fifo => { + // Copy values from the injector into the destination queue. + for i in 0..batch_size { + // Read the task. + let slot = (*block).slots.get_unchecked(offset + i + 1); + slot.wait_write(); + let task = slot.task.get().read().assume_init(); + + // Write it into the destination queue. + dest_buffer.write(dest_b.wrapping_add(i as isize), task); + } + } + + Flavor::Lifo => { + // Copy values from the injector into the destination queue. + for i in 0..batch_size { + // Read the task. + let slot = (*block).slots.get_unchecked(offset + i + 1); + slot.wait_write(); + let task = slot.task.get().read().assume_init(); + + // Write it into the destination queue. + dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task); + } + } + } + + atomic::fence(Ordering::Release); + + // Update the back index in the destination queue. + // + // This ordering could be `Relaxed`, but then thread sanitizer would falsely report + // data races because it doesn't understand fences. + dest.inner + .back + .store(dest_b.wrapping_add(batch_size as isize), Ordering::Release); + + // Destroy the block if we've reached the end, or if another thread wanted to destroy + // but couldn't because we were busy reading from the slot. + if new_offset == BLOCK_CAP { + Block::destroy(block, offset); + } else { + for i in offset..new_offset { + let slot = (*block).slots.get_unchecked(i); + + if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset); + break; + } + } + } + + Steal::Success(task) + } + } + + /// Returns `true` if the queue is empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Injector; + /// + /// let q = Injector::new(); + /// + /// assert!(q.is_empty()); + /// q.push(1); + /// assert!(!q.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + let head = self.head.index.load(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::SeqCst); + head >> SHIFT == tail >> SHIFT + } + + /// Returns the number of tasks in the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Injector; + /// + /// let q = Injector::new(); + /// + /// assert_eq!(q.len(), 0); + /// q.push(1); + /// assert_eq!(q.len(), 1); + /// q.push(1); + /// assert_eq!(q.len(), 2); + /// ``` + pub fn len(&self) -> usize { + loop { + // Load the tail index, then load the head index. + let mut tail = self.tail.index.load(Ordering::SeqCst); + let mut head = self.head.index.load(Ordering::SeqCst); + + // If the tail index didn't change, we've got consistent indices to work with. + if self.tail.index.load(Ordering::SeqCst) == tail { + // Erase the lower bits. + tail &= !((1 << SHIFT) - 1); + head &= !((1 << SHIFT) - 1); + + // Fix up indices if they fall onto block ends. + if (tail >> SHIFT) & (LAP - 1) == LAP - 1 { + tail = tail.wrapping_add(1 << SHIFT); + } + if (head >> SHIFT) & (LAP - 1) == LAP - 1 { + head = head.wrapping_add(1 << SHIFT); + } + + // Rotate indices so that head falls into the first block. + let lap = (head >> SHIFT) / LAP; + tail = tail.wrapping_sub((lap * LAP) << SHIFT); + head = head.wrapping_sub((lap * LAP) << SHIFT); + + // Remove the lower bits. + tail >>= SHIFT; + head >>= SHIFT; + + // Return the difference minus the number of blocks between tail and head. + return tail - head - tail / LAP; + } + } + } +} + +impl Drop for Injector { + fn drop(&mut self) { + let mut head = self.head.index.load(Ordering::Relaxed); + let mut tail = self.tail.index.load(Ordering::Relaxed); + let mut block = self.head.block.load(Ordering::Relaxed); + + // Erase the lower bits. + head &= !((1 << SHIFT) - 1); + tail &= !((1 << SHIFT) - 1); + + unsafe { + // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. + while head != tail { + let offset = (head >> SHIFT) % LAP; + + if offset < BLOCK_CAP { + // Drop the task in the slot. + let slot = (*block).slots.get_unchecked(offset); + let p = &mut *slot.task.get(); + p.as_mut_ptr().drop_in_place(); + } else { + // Deallocate the block and move to the next one. + let next = (*block).next.load(Ordering::Relaxed); + drop(Box::from_raw(block)); + block = next; + } + + head = head.wrapping_add(1 << SHIFT); + } + + // Deallocate the last remaining block. + drop(Box::from_raw(block)); + } + } +} + +impl fmt::Debug for Injector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Worker { .. }") + } +} + +/// Possible outcomes of a steal operation. +/// +/// # Examples +/// +/// There are lots of ways to chain results of steal operations together: +/// +/// ``` +/// use crossbeam_deque::Steal::{self, Empty, Retry, Success}; +/// +/// let collect = |v: Vec>| v.into_iter().collect::>(); +/// +/// assert_eq!(collect(vec![Empty, Empty, Empty]), Empty); +/// assert_eq!(collect(vec![Empty, Retry, Empty]), Retry); +/// assert_eq!(collect(vec![Retry, Success(1), Empty]), Success(1)); +/// +/// assert_eq!(collect(vec![Empty, Empty]).or_else(|| Retry), Retry); +/// assert_eq!(collect(vec![Retry, Empty]).or_else(|| Success(1)), Success(1)); +/// ``` +#[must_use] +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum Steal { + /// The queue was empty at the time of stealing. + Empty, + + /// At least one task was successfully stolen. + Success(T), + + /// The steal operation needs to be retried. + Retry, +} + +impl Steal { + /// Returns `true` if the queue was empty at the time of stealing. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Steal::{Empty, Retry, Success}; + /// + /// assert!(!Success(7).is_empty()); + /// assert!(!Retry::.is_empty()); + /// + /// assert!(Empty::.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match self { + Steal::Empty => true, + _ => false, + } + } + + /// Returns `true` if at least one task was stolen. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Steal::{Empty, Retry, Success}; + /// + /// assert!(!Empty::.is_success()); + /// assert!(!Retry::.is_success()); + /// + /// assert!(Success(7).is_success()); + /// ``` + pub fn is_success(&self) -> bool { + match self { + Steal::Success(_) => true, + _ => false, + } + } + + /// Returns `true` if the steal operation needs to be retried. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Steal::{Empty, Retry, Success}; + /// + /// assert!(!Empty::.is_retry()); + /// assert!(!Success(7).is_retry()); + /// + /// assert!(Retry::.is_retry()); + /// ``` + pub fn is_retry(&self) -> bool { + match self { + Steal::Retry => true, + _ => false, + } + } + + /// Returns the result of the operation, if successful. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Steal::{Empty, Retry, Success}; + /// + /// assert_eq!(Empty::.success(), None); + /// assert_eq!(Retry::.success(), None); + /// + /// assert_eq!(Success(7).success(), Some(7)); + /// ``` + pub fn success(self) -> Option { + match self { + Steal::Success(res) => Some(res), + _ => None, + } + } + + /// If no task was stolen, attempts another steal operation. + /// + /// Returns this steal result if it is `Success`. Otherwise, closure `f` is invoked and then: + /// + /// * If the second steal resulted in `Success`, it is returned. + /// * If both steals were unsuccessful but any resulted in `Retry`, then `Retry` is returned. + /// * If both resulted in `None`, then `None` is returned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_deque::Steal::{Empty, Retry, Success}; + /// + /// assert_eq!(Success(1).or_else(|| Success(2)), Success(1)); + /// assert_eq!(Retry.or_else(|| Success(2)), Success(2)); + /// + /// assert_eq!(Retry.or_else(|| Empty), Retry::); + /// assert_eq!(Empty.or_else(|| Retry), Retry::); + /// + /// assert_eq!(Empty.or_else(|| Empty), Empty::); + /// ``` + pub fn or_else(self, f: F) -> Steal + where + F: FnOnce() -> Steal, + { + match self { + Steal::Empty => f(), + Steal::Success(_) => self, + Steal::Retry => { + if let Steal::Success(res) = f() { + Steal::Success(res) + } else { + Steal::Retry + } + } + } + } +} + +impl fmt::Debug for Steal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Steal::Empty => f.pad("Empty"), + Steal::Success(_) => f.pad("Success(..)"), + Steal::Retry => f.pad("Retry"), + } + } +} + +impl FromIterator> for Steal { + /// Consumes items until a `Success` is found and returns it. + /// + /// If no `Success` was found, but there was at least one `Retry`, then returns `Retry`. + /// Otherwise, `Empty` is returned. + fn from_iter(iter: I) -> Steal + where + I: IntoIterator>, + { + let mut retry = false; + for s in iter { + match &s { + Steal::Empty => {} + Steal::Success(_) => return s, + Steal::Retry => retry = true, + } + } + + if retry { + Steal::Retry + } else { + Steal::Empty + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/src/lib.rs b/third_party/cargo/vendor/crossbeam-deque-0.8.0/src/lib.rs new file mode 100644 index 0000000..dea6153 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/src/lib.rs @@ -0,0 +1,107 @@ +//! Concurrent work-stealing deques. +//! +//! These data structures are most commonly used in work-stealing schedulers. The typical setup +//! involves a number of threads, each having its own FIFO or LIFO queue (*worker*). There is also +//! one global FIFO queue (*injector*) and a list of references to *worker* queues that are able to +//! steal tasks (*stealers*). +//! +//! We spawn a new task onto the scheduler by pushing it into the *injector* queue. Each worker +//! thread waits in a loop until it finds the next task to run and then runs it. To find a task, it +//! first looks into its local *worker* queue, and then into the *injector* and *stealers*. +//! +//! # Queues +//! +//! [`Injector`] is a FIFO queue, where tasks are pushed and stolen from opposite ends. It is +//! shared among threads and is usually the entry point for new tasks. +//! +//! [`Worker`] has two constructors: +//! +//! * [`new_fifo()`] - Creates a FIFO queue, in which tasks are pushed and popped from opposite +//! ends. +//! * [`new_lifo()`] - Creates a LIFO queue, in which tasks are pushed and popped from the same +//! end. +//! +//! Each [`Worker`] is owned by a single thread and supports only push and pop operations. +//! +//! Method [`stealer()`] creates a [`Stealer`] that may be shared among threads and can only steal +//! tasks from its [`Worker`]. Tasks are stolen from the end opposite to where they get pushed. +//! +//! # Stealing +//! +//! Steal operations come in three flavors: +//! +//! 1. [`steal()`] - Steals one task. +//! 2. [`steal_batch()`] - Steals a batch of tasks and moves them into another worker. +//! 3. [`steal_batch_and_pop()`] - Steals a batch of tasks, moves them into another queue, and pops +//! one task from that worker. +//! +//! In contrast to push and pop operations, stealing can spuriously fail with [`Steal::Retry`], in +//! which case the steal operation needs to be retried. +//! +//! # Examples +//! +//! Suppose a thread in a work-stealing scheduler is idle and looking for the next task to run. To +//! find an available task, it might do the following: +//! +//! 1. Try popping one task from the local worker queue. +//! 2. Try stealing a batch of tasks from the global injector queue. +//! 3. Try stealing one task from another thread using the stealer list. +//! +//! An implementation of this work-stealing strategy: +//! +//! ``` +//! use crossbeam_deque::{Injector, Stealer, Worker}; +//! use std::iter; +//! +//! fn find_task( +//! local: &Worker, +//! global: &Injector, +//! stealers: &[Stealer], +//! ) -> Option { +//! // Pop a task from the local queue, if not empty. +//! local.pop().or_else(|| { +//! // Otherwise, we need to look for a task elsewhere. +//! iter::repeat_with(|| { +//! // Try stealing a batch of tasks from the global queue. +//! global.steal_batch_and_pop(local) +//! // Or try stealing a task from one of the other threads. +//! .or_else(|| stealers.iter().map(|s| s.steal()).collect()) +//! }) +//! // Loop while no task was stolen and any steal operation needs to be retried. +//! .find(|s| !s.is_retry()) +//! // Extract the stolen task, if there is one. +//! .and_then(|s| s.success()) +//! }) +//! } +//! ``` +//! +//! [`new_fifo()`]: Worker::new_fifo +//! [`new_lifo()`]: Worker::new_lifo +//! [`stealer()`]: Worker::stealer +//! [`steal()`]: Stealer::steal +//! [`steal_batch()`]: Stealer::steal_batch +//! [`steal_batch_and_pop()`]: Stealer::steal_batch_and_pop + +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms), + allow(dead_code, unused_assignments, unused_variables) + ) +))] +#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] +#![cfg_attr(not(feature = "std"), no_std)] +// matches! requires Rust 1.42 +#![allow(clippy::match_like_matches_macro)] + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "std")] { + use crossbeam_epoch as epoch; + use crossbeam_utils as utils; + + mod deque; + pub use crate::deque::{Injector, Steal, Stealer, Worker}; + } +} diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/fifo.rs b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/fifo.rs new file mode 100644 index 0000000..19a1f58 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/fifo.rs @@ -0,0 +1,338 @@ +use std::sync::atomic::Ordering::SeqCst; +use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::sync::{Arc, Mutex}; + +use crossbeam_deque::Steal::{Empty, Success}; +use crossbeam_deque::Worker; +use crossbeam_utils::thread::scope; +use rand::Rng; + +#[test] +fn smoke() { + let w = Worker::new_fifo(); + let s = w.stealer(); + assert_eq!(w.pop(), None); + assert_eq!(s.steal(), Empty); + + w.push(1); + assert_eq!(w.pop(), Some(1)); + assert_eq!(w.pop(), None); + assert_eq!(s.steal(), Empty); + + w.push(2); + assert_eq!(s.steal(), Success(2)); + assert_eq!(s.steal(), Empty); + assert_eq!(w.pop(), None); + + w.push(3); + w.push(4); + w.push(5); + assert_eq!(s.steal(), Success(3)); + assert_eq!(s.steal(), Success(4)); + assert_eq!(s.steal(), Success(5)); + assert_eq!(s.steal(), Empty); + + w.push(6); + w.push(7); + w.push(8); + w.push(9); + assert_eq!(w.pop(), Some(6)); + assert_eq!(s.steal(), Success(7)); + assert_eq!(w.pop(), Some(8)); + assert_eq!(w.pop(), Some(9)); + assert_eq!(w.pop(), None); +} + +#[test] +fn is_empty() { + let w = Worker::new_fifo(); + let s = w.stealer(); + + assert!(w.is_empty()); + w.push(1); + assert!(!w.is_empty()); + w.push(2); + assert!(!w.is_empty()); + let _ = w.pop(); + assert!(!w.is_empty()); + let _ = w.pop(); + assert!(w.is_empty()); + + assert!(s.is_empty()); + w.push(1); + assert!(!s.is_empty()); + w.push(2); + assert!(!s.is_empty()); + let _ = s.steal(); + assert!(!s.is_empty()); + let _ = s.steal(); + assert!(s.is_empty()); +} + +#[test] +fn spsc() { + const STEPS: usize = 50_000; + + let w = Worker::new_fifo(); + let s = w.stealer(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..STEPS { + loop { + if let Success(v) = s.steal() { + assert_eq!(i, v); + break; + } + } + } + + assert_eq!(s.steal(), Empty); + }); + + for i in 0..STEPS { + w.push(i); + } + }) + .unwrap(); +} + +#[test] +fn stampede() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let w = Worker::new_fifo(); + + for i in 0..COUNT { + w.push(Box::new(i + 1)); + } + let remaining = Arc::new(AtomicUsize::new(COUNT)); + + scope(|scope| { + for _ in 0..THREADS { + let s = w.stealer(); + let remaining = remaining.clone(); + + scope.spawn(move |_| { + let mut last = 0; + while remaining.load(SeqCst) > 0 { + if let Success(x) = s.steal() { + assert!(last < *x); + last = *x; + remaining.fetch_sub(1, SeqCst); + } + } + }); + } + + let mut last = 0; + while remaining.load(SeqCst) > 0 { + if let Some(x) = w.pop() { + assert!(last < *x); + last = *x; + remaining.fetch_sub(1, SeqCst); + } + } + }) + .unwrap(); +} + +#[test] +fn stress() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let w = Worker::new_fifo(); + let done = Arc::new(AtomicBool::new(false)); + let hits = Arc::new(AtomicUsize::new(0)); + + scope(|scope| { + for _ in 0..THREADS { + let s = w.stealer(); + let done = done.clone(); + let hits = hits.clone(); + + scope.spawn(move |_| { + let w2 = Worker::new_fifo(); + + while !done.load(SeqCst) { + if let Success(_) = s.steal() { + hits.fetch_add(1, SeqCst); + } + + let _ = s.steal_batch(&w2); + + if let Success(_) = s.steal_batch_and_pop(&w2) { + hits.fetch_add(1, SeqCst); + } + + while let Some(_) = w2.pop() { + hits.fetch_add(1, SeqCst); + } + } + }); + } + + let mut rng = rand::thread_rng(); + let mut expected = 0; + while expected < COUNT { + if rng.gen_range(0, 3) == 0 { + while let Some(_) = w.pop() { + hits.fetch_add(1, SeqCst); + } + } else { + w.push(expected); + expected += 1; + } + } + + while hits.load(SeqCst) < COUNT { + while let Some(_) = w.pop() { + hits.fetch_add(1, SeqCst); + } + } + done.store(true, SeqCst); + }) + .unwrap(); +} + +#[test] +fn no_starvation() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let w = Worker::new_fifo(); + let done = Arc::new(AtomicBool::new(false)); + let mut all_hits = Vec::new(); + + scope(|scope| { + for _ in 0..THREADS { + let s = w.stealer(); + let done = done.clone(); + let hits = Arc::new(AtomicUsize::new(0)); + all_hits.push(hits.clone()); + + scope.spawn(move |_| { + let w2 = Worker::new_fifo(); + + while !done.load(SeqCst) { + if let Success(_) = s.steal() { + hits.fetch_add(1, SeqCst); + } + + let _ = s.steal_batch(&w2); + + if let Success(_) = s.steal_batch_and_pop(&w2) { + hits.fetch_add(1, SeqCst); + } + + while let Some(_) = w2.pop() { + hits.fetch_add(1, SeqCst); + } + } + }); + } + + let mut rng = rand::thread_rng(); + let mut my_hits = 0; + loop { + for i in 0..rng.gen_range(0, COUNT) { + if rng.gen_range(0, 3) == 0 && my_hits == 0 { + while let Some(_) = w.pop() { + my_hits += 1; + } + } else { + w.push(i); + } + } + + if my_hits > 0 && all_hits.iter().all(|h| h.load(SeqCst) > 0) { + break; + } + } + done.store(true, SeqCst); + }) + .unwrap(); +} + +#[test] +fn destructors() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + const STEPS: usize = 1000; + + struct Elem(usize, Arc>>); + + impl Drop for Elem { + fn drop(&mut self) { + self.1.lock().unwrap().push(self.0); + } + } + + let w = Worker::new_fifo(); + let dropped = Arc::new(Mutex::new(Vec::new())); + let remaining = Arc::new(AtomicUsize::new(COUNT)); + + for i in 0..COUNT { + w.push(Elem(i, dropped.clone())); + } + + scope(|scope| { + for _ in 0..THREADS { + let remaining = remaining.clone(); + let s = w.stealer(); + + scope.spawn(move |_| { + let w2 = Worker::new_fifo(); + let mut cnt = 0; + + while cnt < STEPS { + if let Success(_) = s.steal() { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + + let _ = s.steal_batch(&w2); + + if let Success(_) = s.steal_batch_and_pop(&w2) { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + + while let Some(_) = w2.pop() { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + } + }); + } + + for _ in 0..STEPS { + if let Some(_) = w.pop() { + remaining.fetch_sub(1, SeqCst); + } + } + }) + .unwrap(); + + let rem = remaining.load(SeqCst); + assert!(rem > 0); + + { + let mut v = dropped.lock().unwrap(); + assert_eq!(v.len(), COUNT - rem); + v.clear(); + } + + drop(w); + + { + let mut v = dropped.lock().unwrap(); + assert_eq!(v.len(), rem); + v.sort(); + for pair in v.windows(2) { + assert_eq!(pair[0] + 1, pair[1]); + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/injector.rs b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/injector.rs new file mode 100644 index 0000000..0165e1a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/injector.rs @@ -0,0 +1,349 @@ +use std::sync::atomic::Ordering::SeqCst; +use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::sync::{Arc, Mutex}; + +use crossbeam_deque::Steal::{Empty, Success}; +use crossbeam_deque::{Injector, Worker}; +use crossbeam_utils::thread::scope; +use rand::Rng; + +#[test] +fn smoke() { + let q = Injector::new(); + assert_eq!(q.steal(), Empty); + + q.push(1); + q.push(2); + assert_eq!(q.steal(), Success(1)); + assert_eq!(q.steal(), Success(2)); + assert_eq!(q.steal(), Empty); + + q.push(3); + assert_eq!(q.steal(), Success(3)); + assert_eq!(q.steal(), Empty); +} + +#[test] +fn is_empty() { + let q = Injector::new(); + assert!(q.is_empty()); + + q.push(1); + assert!(!q.is_empty()); + q.push(2); + assert!(!q.is_empty()); + + let _ = q.steal(); + assert!(!q.is_empty()); + let _ = q.steal(); + assert!(q.is_empty()); + + q.push(3); + assert!(!q.is_empty()); + let _ = q.steal(); + assert!(q.is_empty()); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let q = Injector::new(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + loop { + if let Success(v) = q.steal() { + assert_eq!(i, v); + break; + } + } + } + + assert_eq!(q.steal(), Empty); + }); + + for i in 0..COUNT { + q.push(i); + } + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let q = Injector::new(); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + q.push(i); + } + }); + } + + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + loop { + if let Success(n) = q.steal() { + v[n].fetch_add(1, SeqCst); + break; + } + } + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(SeqCst), THREADS); + } +} + +#[test] +fn stampede() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let q = Injector::new(); + + for i in 0..COUNT { + q.push(Box::new(i + 1)); + } + let remaining = Arc::new(AtomicUsize::new(COUNT)); + + scope(|scope| { + for _ in 0..THREADS { + let remaining = remaining.clone(); + let q = &q; + + scope.spawn(move |_| { + let mut last = 0; + while remaining.load(SeqCst) > 0 { + if let Success(x) = q.steal() { + assert!(last < *x); + last = *x; + remaining.fetch_sub(1, SeqCst); + } + } + }); + } + + let mut last = 0; + while remaining.load(SeqCst) > 0 { + if let Success(x) = q.steal() { + assert!(last < *x); + last = *x; + remaining.fetch_sub(1, SeqCst); + } + } + }) + .unwrap(); +} + +#[test] +fn stress() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let q = Injector::new(); + let done = Arc::new(AtomicBool::new(false)); + let hits = Arc::new(AtomicUsize::new(0)); + + scope(|scope| { + for _ in 0..THREADS { + let done = done.clone(); + let hits = hits.clone(); + let q = &q; + + scope.spawn(move |_| { + let w2 = Worker::new_fifo(); + + while !done.load(SeqCst) { + if let Success(_) = q.steal() { + hits.fetch_add(1, SeqCst); + } + + let _ = q.steal_batch(&w2); + + if let Success(_) = q.steal_batch_and_pop(&w2) { + hits.fetch_add(1, SeqCst); + } + + while let Some(_) = w2.pop() { + hits.fetch_add(1, SeqCst); + } + } + }); + } + + let mut rng = rand::thread_rng(); + let mut expected = 0; + while expected < COUNT { + if rng.gen_range(0, 3) == 0 { + while let Success(_) = q.steal() { + hits.fetch_add(1, SeqCst); + } + } else { + q.push(expected); + expected += 1; + } + } + + while hits.load(SeqCst) < COUNT { + while let Success(_) = q.steal() { + hits.fetch_add(1, SeqCst); + } + } + done.store(true, SeqCst); + }) + .unwrap(); +} + +#[test] +fn no_starvation() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let q = Injector::new(); + let done = Arc::new(AtomicBool::new(false)); + let mut all_hits = Vec::new(); + + scope(|scope| { + for _ in 0..THREADS { + let done = done.clone(); + let hits = Arc::new(AtomicUsize::new(0)); + all_hits.push(hits.clone()); + let q = &q; + + scope.spawn(move |_| { + let w2 = Worker::new_fifo(); + + while !done.load(SeqCst) { + if let Success(_) = q.steal() { + hits.fetch_add(1, SeqCst); + } + + let _ = q.steal_batch(&w2); + + if let Success(_) = q.steal_batch_and_pop(&w2) { + hits.fetch_add(1, SeqCst); + } + + while let Some(_) = w2.pop() { + hits.fetch_add(1, SeqCst); + } + } + }); + } + + let mut rng = rand::thread_rng(); + let mut my_hits = 0; + loop { + for i in 0..rng.gen_range(0, COUNT) { + if rng.gen_range(0, 3) == 0 && my_hits == 0 { + while let Success(_) = q.steal() { + my_hits += 1; + } + } else { + q.push(i); + } + } + + if my_hits > 0 && all_hits.iter().all(|h| h.load(SeqCst) > 0) { + break; + } + } + done.store(true, SeqCst); + }) + .unwrap(); +} + +#[test] +fn destructors() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + const STEPS: usize = 1000; + + struct Elem(usize, Arc>>); + + impl Drop for Elem { + fn drop(&mut self) { + self.1.lock().unwrap().push(self.0); + } + } + + let q = Injector::new(); + let dropped = Arc::new(Mutex::new(Vec::new())); + let remaining = Arc::new(AtomicUsize::new(COUNT)); + + for i in 0..COUNT { + q.push(Elem(i, dropped.clone())); + } + + scope(|scope| { + for _ in 0..THREADS { + let remaining = remaining.clone(); + let q = &q; + + scope.spawn(move |_| { + let w2 = Worker::new_fifo(); + let mut cnt = 0; + + while cnt < STEPS { + if let Success(_) = q.steal() { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + + let _ = q.steal_batch(&w2); + + if let Success(_) = q.steal_batch_and_pop(&w2) { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + + while let Some(_) = w2.pop() { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + } + }); + } + + for _ in 0..STEPS { + if let Success(_) = q.steal() { + remaining.fetch_sub(1, SeqCst); + } + } + }) + .unwrap(); + + let rem = remaining.load(SeqCst); + assert!(rem > 0); + + { + let mut v = dropped.lock().unwrap(); + assert_eq!(v.len(), COUNT - rem); + v.clear(); + } + + drop(q); + + { + let mut v = dropped.lock().unwrap(); + assert_eq!(v.len(), rem); + v.sort(); + for pair in v.windows(2) { + assert_eq!(pair[0] + 1, pair[1]); + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/lifo.rs b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/lifo.rs new file mode 100644 index 0000000..d7e498a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/lifo.rs @@ -0,0 +1,338 @@ +use std::sync::atomic::Ordering::SeqCst; +use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::sync::{Arc, Mutex}; + +use crossbeam_deque::Steal::{Empty, Success}; +use crossbeam_deque::Worker; +use crossbeam_utils::thread::scope; +use rand::Rng; + +#[test] +fn smoke() { + let w = Worker::new_lifo(); + let s = w.stealer(); + assert_eq!(w.pop(), None); + assert_eq!(s.steal(), Empty); + + w.push(1); + assert_eq!(w.pop(), Some(1)); + assert_eq!(w.pop(), None); + assert_eq!(s.steal(), Empty); + + w.push(2); + assert_eq!(s.steal(), Success(2)); + assert_eq!(s.steal(), Empty); + assert_eq!(w.pop(), None); + + w.push(3); + w.push(4); + w.push(5); + assert_eq!(s.steal(), Success(3)); + assert_eq!(s.steal(), Success(4)); + assert_eq!(s.steal(), Success(5)); + assert_eq!(s.steal(), Empty); + + w.push(6); + w.push(7); + w.push(8); + w.push(9); + assert_eq!(w.pop(), Some(9)); + assert_eq!(s.steal(), Success(6)); + assert_eq!(w.pop(), Some(8)); + assert_eq!(w.pop(), Some(7)); + assert_eq!(w.pop(), None); +} + +#[test] +fn is_empty() { + let w = Worker::new_lifo(); + let s = w.stealer(); + + assert!(w.is_empty()); + w.push(1); + assert!(!w.is_empty()); + w.push(2); + assert!(!w.is_empty()); + let _ = w.pop(); + assert!(!w.is_empty()); + let _ = w.pop(); + assert!(w.is_empty()); + + assert!(s.is_empty()); + w.push(1); + assert!(!s.is_empty()); + w.push(2); + assert!(!s.is_empty()); + let _ = s.steal(); + assert!(!s.is_empty()); + let _ = s.steal(); + assert!(s.is_empty()); +} + +#[test] +fn spsc() { + const STEPS: usize = 50_000; + + let w = Worker::new_lifo(); + let s = w.stealer(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..STEPS { + loop { + if let Success(v) = s.steal() { + assert_eq!(i, v); + break; + } + } + } + + assert_eq!(s.steal(), Empty); + }); + + for i in 0..STEPS { + w.push(i); + } + }) + .unwrap(); +} + +#[test] +fn stampede() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let w = Worker::new_lifo(); + + for i in 0..COUNT { + w.push(Box::new(i + 1)); + } + let remaining = Arc::new(AtomicUsize::new(COUNT)); + + scope(|scope| { + for _ in 0..THREADS { + let s = w.stealer(); + let remaining = remaining.clone(); + + scope.spawn(move |_| { + let mut last = 0; + while remaining.load(SeqCst) > 0 { + if let Success(x) = s.steal() { + assert!(last < *x); + last = *x; + remaining.fetch_sub(1, SeqCst); + } + } + }); + } + + let mut last = COUNT + 1; + while remaining.load(SeqCst) > 0 { + if let Some(x) = w.pop() { + assert!(last > *x); + last = *x; + remaining.fetch_sub(1, SeqCst); + } + } + }) + .unwrap(); +} + +#[test] +fn stress() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let w = Worker::new_lifo(); + let done = Arc::new(AtomicBool::new(false)); + let hits = Arc::new(AtomicUsize::new(0)); + + scope(|scope| { + for _ in 0..THREADS { + let s = w.stealer(); + let done = done.clone(); + let hits = hits.clone(); + + scope.spawn(move |_| { + let w2 = Worker::new_lifo(); + + while !done.load(SeqCst) { + if let Success(_) = s.steal() { + hits.fetch_add(1, SeqCst); + } + + let _ = s.steal_batch(&w2); + + if let Success(_) = s.steal_batch_and_pop(&w2) { + hits.fetch_add(1, SeqCst); + } + + while let Some(_) = w2.pop() { + hits.fetch_add(1, SeqCst); + } + } + }); + } + + let mut rng = rand::thread_rng(); + let mut expected = 0; + while expected < COUNT { + if rng.gen_range(0, 3) == 0 { + while let Some(_) = w.pop() { + hits.fetch_add(1, SeqCst); + } + } else { + w.push(expected); + expected += 1; + } + } + + while hits.load(SeqCst) < COUNT { + while let Some(_) = w.pop() { + hits.fetch_add(1, SeqCst); + } + } + done.store(true, SeqCst); + }) + .unwrap(); +} + +#[test] +fn no_starvation() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + + let w = Worker::new_lifo(); + let done = Arc::new(AtomicBool::new(false)); + let mut all_hits = Vec::new(); + + scope(|scope| { + for _ in 0..THREADS { + let s = w.stealer(); + let done = done.clone(); + let hits = Arc::new(AtomicUsize::new(0)); + all_hits.push(hits.clone()); + + scope.spawn(move |_| { + let w2 = Worker::new_lifo(); + + while !done.load(SeqCst) { + if let Success(_) = s.steal() { + hits.fetch_add(1, SeqCst); + } + + let _ = s.steal_batch(&w2); + + if let Success(_) = s.steal_batch_and_pop(&w2) { + hits.fetch_add(1, SeqCst); + } + + while let Some(_) = w2.pop() { + hits.fetch_add(1, SeqCst); + } + } + }); + } + + let mut rng = rand::thread_rng(); + let mut my_hits = 0; + loop { + for i in 0..rng.gen_range(0, COUNT) { + if rng.gen_range(0, 3) == 0 && my_hits == 0 { + while let Some(_) = w.pop() { + my_hits += 1; + } + } else { + w.push(i); + } + } + + if my_hits > 0 && all_hits.iter().all(|h| h.load(SeqCst) > 0) { + break; + } + } + done.store(true, SeqCst); + }) + .unwrap(); +} + +#[test] +fn destructors() { + const THREADS: usize = 8; + const COUNT: usize = 50_000; + const STEPS: usize = 1000; + + struct Elem(usize, Arc>>); + + impl Drop for Elem { + fn drop(&mut self) { + self.1.lock().unwrap().push(self.0); + } + } + + let w = Worker::new_lifo(); + let dropped = Arc::new(Mutex::new(Vec::new())); + let remaining = Arc::new(AtomicUsize::new(COUNT)); + + for i in 0..COUNT { + w.push(Elem(i, dropped.clone())); + } + + scope(|scope| { + for _ in 0..THREADS { + let remaining = remaining.clone(); + let s = w.stealer(); + + scope.spawn(move |_| { + let w2 = Worker::new_lifo(); + let mut cnt = 0; + + while cnt < STEPS { + if let Success(_) = s.steal() { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + + let _ = s.steal_batch(&w2); + + if let Success(_) = s.steal_batch_and_pop(&w2) { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + + while let Some(_) = w2.pop() { + cnt += 1; + remaining.fetch_sub(1, SeqCst); + } + } + }); + } + + for _ in 0..STEPS { + if let Some(_) = w.pop() { + remaining.fetch_sub(1, SeqCst); + } + } + }) + .unwrap(); + + let rem = remaining.load(SeqCst); + assert!(rem > 0); + + { + let mut v = dropped.lock().unwrap(); + assert_eq!(v.len(), COUNT - rem); + v.clear(); + } + + drop(w); + + { + let mut v = dropped.lock().unwrap(); + assert_eq!(v.len(), rem); + v.sort(); + for pair in v.windows(2) { + assert_eq!(pair[0] + 1, pair[1]); + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/steal.rs b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/steal.rs new file mode 100644 index 0000000..af24998 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-deque-0.8.0/tests/steal.rs @@ -0,0 +1,212 @@ +use crossbeam_deque::Steal::Success; +use crossbeam_deque::{Injector, Worker}; + +#[test] +fn steal_fifo() { + let w = Worker::new_fifo(); + for i in 1..=3 { + w.push(i); + } + + let s = w.stealer(); + assert_eq!(s.steal(), Success(1)); + assert_eq!(s.steal(), Success(2)); + assert_eq!(s.steal(), Success(3)); +} + +#[test] +fn steal_lifo() { + let w = Worker::new_lifo(); + for i in 1..=3 { + w.push(i); + } + + let s = w.stealer(); + assert_eq!(s.steal(), Success(1)); + assert_eq!(s.steal(), Success(2)); + assert_eq!(s.steal(), Success(3)); +} + +#[test] +fn steal_injector() { + let q = Injector::new(); + for i in 1..=3 { + q.push(i); + } + + assert_eq!(q.steal(), Success(1)); + assert_eq!(q.steal(), Success(2)); + assert_eq!(q.steal(), Success(3)); +} + +#[test] +fn steal_batch_fifo_fifo() { + let w = Worker::new_fifo(); + for i in 1..=4 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_fifo(); + + assert_eq!(s.steal_batch(&w2), Success(())); + assert_eq!(w2.pop(), Some(1)); + assert_eq!(w2.pop(), Some(2)); +} + +#[test] +fn steal_batch_lifo_lifo() { + let w = Worker::new_lifo(); + for i in 1..=4 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_lifo(); + + assert_eq!(s.steal_batch(&w2), Success(())); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(1)); +} + +#[test] +fn steal_batch_fifo_lifo() { + let w = Worker::new_fifo(); + for i in 1..=4 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_lifo(); + + assert_eq!(s.steal_batch(&w2), Success(())); + assert_eq!(w2.pop(), Some(1)); + assert_eq!(w2.pop(), Some(2)); +} + +#[test] +fn steal_batch_lifo_fifo() { + let w = Worker::new_lifo(); + for i in 1..=4 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_fifo(); + + assert_eq!(s.steal_batch(&w2), Success(())); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(1)); +} + +#[test] +fn steal_batch_injector_fifo() { + let q = Injector::new(); + for i in 1..=4 { + q.push(i); + } + + let w2 = Worker::new_fifo(); + assert_eq!(q.steal_batch(&w2), Success(())); + assert_eq!(w2.pop(), Some(1)); + assert_eq!(w2.pop(), Some(2)); +} + +#[test] +fn steal_batch_injector_lifo() { + let q = Injector::new(); + for i in 1..=4 { + q.push(i); + } + + let w2 = Worker::new_lifo(); + assert_eq!(q.steal_batch(&w2), Success(())); + assert_eq!(w2.pop(), Some(1)); + assert_eq!(w2.pop(), Some(2)); +} + +#[test] +fn steal_batch_and_pop_fifo_fifo() { + let w = Worker::new_fifo(); + for i in 1..=6 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_fifo(); + + assert_eq!(s.steal_batch_and_pop(&w2), Success(1)); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(3)); +} + +#[test] +fn steal_batch_and_pop_lifo_lifo() { + let w = Worker::new_lifo(); + for i in 1..=6 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_lifo(); + + assert_eq!(s.steal_batch_and_pop(&w2), Success(3)); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(1)); +} + +#[test] +fn steal_batch_and_pop_fifo_lifo() { + let w = Worker::new_fifo(); + for i in 1..=6 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_lifo(); + + assert_eq!(s.steal_batch_and_pop(&w2), Success(1)); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(3)); +} + +#[test] +fn steal_batch_and_pop_lifo_fifo() { + let w = Worker::new_lifo(); + for i in 1..=6 { + w.push(i); + } + + let s = w.stealer(); + let w2 = Worker::new_fifo(); + + assert_eq!(s.steal_batch_and_pop(&w2), Success(3)); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(1)); +} + +#[test] +fn steal_batch_and_pop_injector_fifo() { + let q = Injector::new(); + for i in 1..=6 { + q.push(i); + } + + let w2 = Worker::new_fifo(); + assert_eq!(q.steal_batch_and_pop(&w2), Success(1)); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(3)); +} + +#[test] +fn steal_batch_and_pop_injector_lifo() { + let q = Injector::new(); + for i in 1..=6 { + q.push(i); + } + + let w2 = Worker::new_lifo(); + assert_eq!(q.steal_batch_and_pop(&w2), Success(1)); + assert_eq!(w2.pop(), Some(2)); + assert_eq!(w2.pop(), Some(3)); +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.8.2/BUILD.bazel b/third_party/cargo/vendor/crossbeam-epoch-0.8.2/BUILD.bazel index f527c16..0aa4ac5 100644 --- a/third_party/cargo/vendor/crossbeam-epoch-0.8.2/BUILD.bazel +++ b/third_party/cargo/vendor/crossbeam-epoch-0.8.2/BUILD.bazel @@ -68,7 +68,7 @@ rust_library( "//third_party/cargo/vendor/crossbeam-utils-0.7.2:crossbeam_utils", "//third_party/cargo/vendor/lazy_static-1.4.0:lazy_static", "//third_party/cargo/vendor/maybe-uninit-2.0.0:maybe_uninit", - "//third_party/cargo/vendor/memoffset-0.5.4:memoffset", + "//third_party/cargo/vendor/memoffset-0.5.6:memoffset", "//third_party/cargo/vendor/scopeguard-1.1.0:scopeguard", ], ) diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/.cargo-checksum.json new file mode 100644 index 0000000..ebdb01f --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"be05797b229bfb486c7b0432093aedc6be1129543979aad352f3e2c8b6ecb0e1","Cargo.lock":"701958899c3aeb45c5a8e46c7478f8899b85649c7f66ce63d0e6a5c3209f1ec1","Cargo.toml":"91e77f6969e25d10b83e69dc1274321329045712c7e7d389be20bc250b4409c1","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"dbab340cd33d900cf38d5bdee509e09ef7ec3c490c7b47931e840cefec1f1d53","benches/defer.rs":"c330b704d96b2ad1aed29f72c37a99da534adef8cb06a3976d5f93bf567abb20","benches/flush.rs":"0389ac6c473632f0e93c962f223404cc360257f6699b4ec90b9b3be16bb6d74f","benches/pin.rs":"80f9e65ba04a2ddec7a330172d0b0fbc698e20c221b3d8cdc70cc42e3b9099d1","examples/sanitize.rs":"30001550746a54d6a377f8913fa41c72bf85140d7e8777e07c38491a4e31664b","examples/treiber_stack.rs":"ce4a5f8da67f8497ab0321aaa1aed032ae343c0d36500f2e55a24e76230dedcb","src/atomic.rs":"b92192024336203b865496c8c398ce53ec15bd401eb98c85fa3634bcbd126f86","src/collector.rs":"c310be652b837f73048663c08e872bc14f64b4ae9030c34fe737e6fe0e2d768b","src/default.rs":"b2c9a86b392dc3d687b01abee61b479a6043c5c654a22b79e880f4226dcf65ae","src/deferred.rs":"1df28c99dad1e22ecad7515e829b78ba54bdbbce07ad0b7b122db22b7b215a1e","src/epoch.rs":"76dd63356d5bc52e741883d39abb636e4ccb04d20499fb2a0ce797bb81aa4e91","src/guard.rs":"55c56ca1b2fbc067ae21108f0f7de4be91e5b41df2492055b635ed436782dd52","src/internal.rs":"c6f0a79fb8bccbcc58c5db1135a9bc8a6fc69affaf346c5afb69aa725b46e2b7","src/lib.rs":"a4655d14fce9c4c028d9dd0c5d8ea56064eec1dbc0aef400a236d4ace3f49c7c","src/sync/list.rs":"b16e6dc7c2f94c8682926ea8627352f49ab2b464245b241cfc77b72fa1878dd3","src/sync/mod.rs":"2da979ca3a2293f7626a2e6a9ab2fad758d92e3d2bed6cc712ef59eeeea87eab","src/sync/queue.rs":"225d4878142c245226262346c18434436ffc35f14f15a600a3006758449cccb0"},"package":"a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/BUILD.bazel b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/BUILD.bazel new file mode 100644 index 0000000..89b51b0 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/BUILD.bazel @@ -0,0 +1,74 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "defer" with type "bench" omitted + +# Unsupported target "flush" with type "bench" omitted + +# Unsupported target "pin" with type "bench" omitted + +# Unsupported target "sanitize" with type "example" omitted + +# Unsupported target "treiber_stack" with type "example" omitted + +rust_library( + name = "crossbeam_epoch", + srcs = glob(["**/*.rs"]), + crate_features = [ + "alloc", + "lazy_static", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + proc_macro_deps = [ + "//third_party/cargo/vendor/const_fn-0.4.5:const_fn", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.9.1", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/cfg-if-1.0.0:cfg_if", + "//third_party/cargo/vendor/crossbeam-utils-0.8.1:crossbeam_utils", + "//third_party/cargo/vendor/lazy_static-1.4.0:lazy_static", + "//third_party/cargo/vendor/memoffset-0.6.1:memoffset", + "//third_party/cargo/vendor/scopeguard-1.1.0:scopeguard", + ], +) diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/CHANGELOG.md new file mode 100644 index 0000000..0e154a6 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/CHANGELOG.md @@ -0,0 +1,109 @@ +# Version 0.9.1 + +- Bump `memoffset` dependency to version 0.6. (#592) + +# Version 0.9.0 + +- Bump the minimum supported Rust version to 1.36. +- Support dynamically sized types. + +# Version 0.8.2 + +- Fix bug in release (yanking 0.8.1) + +# Version 0.8.1 + +- Bump `autocfg` dependency to version 1.0. (#460) +- Reduce stall in list iteration. (#376) +- Stop stealing from the same deque. (#448) +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) +- Fix use-after-free in lock-free queue. (#466) + +# Version 0.8.0 + +- Bump the minimum required version to 1.28. +- Fix breakage with nightly feature due to rust-lang/rust#65214. +- Make `Atomic::null()` const function at 1.31+. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.7.2 + +- Add `Atomic::into_owned()`. +- Update `memoffset` dependency. + +# Version 0.7.1 + +- Add `Shared::deref_mut()`. +- Add a Treiber stack to examples. + +# Version 0.7.0 + +- Remove `Guard::clone()`. +- Bump dependencies. + +# Version 0.6.1 + +- Update `crossbeam-utils` to `0.6`. + +# Version 0.6.0 + +- `defer` now requires `F: Send + 'static`. +- Bump the minimum Rust version to 1.26. +- Pinning while TLS is tearing down does not fail anymore. +- Rename `Handle` to `LocalHandle`. +- Add `defer_unchecked` and `defer_destroy`. +- Remove `Clone` impl for `LocalHandle`. + +# Version 0.5.2 + +- Update `crossbeam-utils` to `0.5`. + +# Version 0.5.1 + +- Fix compatibility with the latest Rust nightly. + +# Version 0.5.0 + +- Update `crossbeam-utils` to `0.4`. +- Specify the minimum Rust version to `1.25.0`. + +# Version 0.4.3 + +- Downgrade `crossbeam-utils` to `0.3` because it was a breaking change. + +# Version 0.4.2 + +- Expose the `Pointer` trait. +- Warn missing docs and missing debug impls. +- Update `crossbeam-utils` to `0.4`. + +# Version 0.4.1 + +- Add `Debug` impls for `Collector`, `Handle`, and `Guard`. +- Add `load_consume` to `Atomic`. +- Rename `Collector::handle` to `Collector::register`. +- Remove the `Send` implementation for `Handle` (this was a bug). Only + `Collector`s can be shared among multiple threads, while `Handle`s and + `Guard`s must stay within the thread in which they were created. + +# Version 0.4.0 + +- Update dependencies. +- Remove support for Rust 1.13. + +# Version 0.3.0 + +- Add support for Rust 1.13. +- Improve documentation for CAS. + +# Version 0.2.0 + +- Add method `Owned::into_box`. +- Fix a use-after-free bug in `Local::finalize`. +- Fix an ordering bug in `Global::push_bag`. +- Fix a bug in calculating distance between epochs. +- Remove `impl Into> for Owned`. + +# Version 0.1.0 + +- First version of the new epoch-based GC. diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/Cargo.lock b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/Cargo.lock new file mode 100644 index 0000000..baebea0 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/Cargo.lock @@ -0,0 +1,140 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const_fn" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" + +[[package]] +name = "crossbeam-epoch" +version = "0.9.1" +dependencies = [ + "cfg-if 1.0.0", + "const_fn", + "crossbeam-utils", + "lazy_static", + "memoffset", + "rand", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" + +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/Cargo.toml b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/Cargo.toml new file mode 100644 index 0000000..e14da07 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/Cargo.toml @@ -0,0 +1,54 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "crossbeam-epoch" +version = "0.9.1" +authors = ["The Crossbeam Project Developers"] +description = "Epoch-based garbage collection" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch" +documentation = "https://docs.rs/crossbeam-epoch" +readme = "README.md" +keywords = ["lock-free", "rcu", "atomic", "garbage"] +categories = ["concurrency", "memory-management", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dependencies.cfg-if] +version = "1" + +[dependencies.const_fn] +version = "0.4" + +[dependencies.crossbeam-utils] +version = "0.8" +default-features = false + +[dependencies.lazy_static] +version = "1.4.0" +optional = true + +[dependencies.memoffset] +version = "0.6" + +[dependencies.scopeguard] +version = "1.1.0" +default-features = false +[dev-dependencies.rand] +version = "0.7.3" + +[features] +alloc = [] +default = ["std"] +nightly = ["crossbeam-utils/nightly"] +sanitize = [] +std = ["alloc", "crossbeam-utils/std", "lazy_static"] diff --git a/third_party/cargo/vendor/deflate-0.8.4/LICENSE-APACHE b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/deflate-0.8.4/LICENSE-APACHE rename to third_party/cargo/vendor/crossbeam-epoch-0.9.1/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/LICENSE-MIT b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/LICENSE-MIT new file mode 100644 index 0000000..068d491 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/LICENSE-MIT @@ -0,0 +1,27 @@ +The MIT License (MIT) + +Copyright (c) 2019 The Crossbeam Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/README.md b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/README.md new file mode 100644 index 0000000..7e3d3a9 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/README.md @@ -0,0 +1,53 @@ +# Crossbeam Epoch + +[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( +https://github.com/crossbeam-rs/crossbeam/actions) +[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch#license) +[![Cargo](https://img.shields.io/crates/v/crossbeam-epoch.svg)]( +https://crates.io/crates/crossbeam-epoch) +[![Documentation](https://docs.rs/crossbeam-epoch/badge.svg)]( +https://docs.rs/crossbeam-epoch) +[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides epoch-based garbage collection for building concurrent data structures. + +When a thread removes an object from a concurrent data structure, other threads +may be still using pointers to it at the same time, so it cannot be destroyed +immediately. Epoch-based GC is an efficient mechanism for deferring destruction of +shared objects until no pointers to them can exist. + +Everything in this crate except the global GC can be used in `no_std` environments, provided that +features `alloc` and `nightly` are enabled. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-epoch = "0.9" +``` + +## Compatibility + +Crossbeam Epoch supports stable Rust releases going back at least six months, +and every time the minimum supported Rust version is increased, a new minor +version is released. Currently, the minimum supported Rust version is 1.36. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/defer.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/defer.rs new file mode 100644 index 0000000..246f907 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/defer.rs @@ -0,0 +1,69 @@ +#![feature(test)] + +extern crate test; + +use crossbeam_epoch::{self as epoch, Owned}; +use crossbeam_utils::thread::scope; +use test::Bencher; + +#[bench] +fn single_alloc_defer_free(b: &mut Bencher) { + b.iter(|| { + let guard = &epoch::pin(); + let p = Owned::new(1).into_shared(guard); + unsafe { + guard.defer_destroy(p); + } + }); +} + +#[bench] +fn single_defer(b: &mut Bencher) { + b.iter(|| { + let guard = &epoch::pin(); + guard.defer(move || ()); + }); +} + +#[bench] +fn multi_alloc_defer_free(b: &mut Bencher) { + const THREADS: usize = 16; + const STEPS: usize = 10_000; + + b.iter(|| { + scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + for _ in 0..STEPS { + let guard = &epoch::pin(); + let p = Owned::new(1).into_shared(guard); + unsafe { + guard.defer_destroy(p); + } + } + }); + } + }) + .unwrap(); + }); +} + +#[bench] +fn multi_defer(b: &mut Bencher) { + const THREADS: usize = 16; + const STEPS: usize = 10_000; + + b.iter(|| { + scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + for _ in 0..STEPS { + let guard = &epoch::pin(); + guard.defer(move || ()); + } + }); + } + }) + .unwrap(); + }); +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/flush.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/flush.rs new file mode 100644 index 0000000..99aab19 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/flush.rs @@ -0,0 +1,52 @@ +#![feature(test)] + +extern crate test; + +use std::sync::Barrier; + +use crossbeam_epoch as epoch; +use crossbeam_utils::thread::scope; +use test::Bencher; + +#[bench] +fn single_flush(b: &mut Bencher) { + const THREADS: usize = 16; + + let start = Barrier::new(THREADS + 1); + let end = Barrier::new(THREADS + 1); + + scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + epoch::pin(); + start.wait(); + end.wait(); + }); + } + + start.wait(); + b.iter(|| epoch::pin().flush()); + end.wait(); + }) + .unwrap(); +} + +#[bench] +fn multi_flush(b: &mut Bencher) { + const THREADS: usize = 16; + const STEPS: usize = 10_000; + + b.iter(|| { + scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + for _ in 0..STEPS { + let guard = &epoch::pin(); + guard.flush(); + } + }); + } + }) + .unwrap(); + }); +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/pin.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/pin.rs new file mode 100644 index 0000000..0dff4c5 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/benches/pin.rs @@ -0,0 +1,31 @@ +#![feature(test)] + +extern crate test; + +use crossbeam_epoch as epoch; +use crossbeam_utils::thread::scope; +use test::Bencher; + +#[bench] +fn single_pin(b: &mut Bencher) { + b.iter(|| epoch::pin()); +} + +#[bench] +fn multi_pin(b: &mut Bencher) { + const THREADS: usize = 16; + const STEPS: usize = 100_000; + + b.iter(|| { + scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + for _ in 0..STEPS { + epoch::pin(); + } + }); + } + }) + .unwrap(); + }); +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/examples/sanitize.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/examples/sanitize.rs new file mode 100644 index 0000000..5110f8a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/examples/sanitize.rs @@ -0,0 +1,66 @@ +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed}; +use std::sync::Arc; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_epoch::{self as epoch, Atomic, Collector, LocalHandle, Owned, Shared}; +use rand::Rng; + +fn worker(a: Arc>, handle: LocalHandle) -> usize { + let mut rng = rand::thread_rng(); + let mut sum = 0; + + if rng.gen() { + thread::sleep(Duration::from_millis(1)); + } + let timeout = Duration::from_millis(rng.gen_range(0, 10)); + let now = Instant::now(); + + while now.elapsed() < timeout { + for _ in 0..100 { + let guard = &handle.pin(); + guard.flush(); + + let val = if rng.gen() { + let p = a.swap(Owned::new(AtomicUsize::new(sum)), AcqRel, guard); + unsafe { + guard.defer_destroy(p); + guard.flush(); + p.deref().load(Relaxed) + } + } else { + let p = a.load(Acquire, guard); + unsafe { p.deref().fetch_add(sum, Relaxed) } + }; + + sum = sum.wrapping_add(val); + } + } + + sum +} + +fn main() { + for _ in 0..100 { + let collector = Collector::new(); + let a = Arc::new(Atomic::new(AtomicUsize::new(777))); + + let threads = (0..16) + .map(|_| { + let a = a.clone(); + let c = collector.clone(); + thread::spawn(move || worker(a, c.register())) + }) + .collect::>(); + + for t in threads { + t.join().unwrap(); + } + + unsafe { + a.swap(Shared::null(), AcqRel, epoch::unprotected()) + .into_owned(); + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/examples/treiber_stack.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/examples/treiber_stack.rs new file mode 100644 index 0000000..a2c3c16 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/examples/treiber_stack.rs @@ -0,0 +1,107 @@ +use std::mem::ManuallyDrop; +use std::ptr; +use std::sync::atomic::Ordering::{Acquire, Relaxed, Release}; + +use crossbeam_epoch::{self as epoch, Atomic, Owned}; +use crossbeam_utils::thread::scope; + +/// Treiber's lock-free stack. +/// +/// Usable with any number of producers and consumers. +#[derive(Debug)] +pub struct TreiberStack { + head: Atomic>, +} + +#[derive(Debug)] +struct Node { + data: ManuallyDrop, + next: Atomic>, +} + +impl TreiberStack { + /// Creates a new, empty stack. + pub fn new() -> TreiberStack { + TreiberStack { + head: Atomic::null(), + } + } + + /// Pushes a value on top of the stack. + pub fn push(&self, t: T) { + let mut n = Owned::new(Node { + data: ManuallyDrop::new(t), + next: Atomic::null(), + }); + + let guard = epoch::pin(); + + loop { + let head = self.head.load(Relaxed, &guard); + n.next.store(head, Relaxed); + + match self.head.compare_and_set(head, n, Release, &guard) { + Ok(_) => break, + Err(e) => n = e.new, + } + } + } + + /// Attempts to pop the top element from the stack. + /// + /// Returns `None` if the stack is empty. + pub fn pop(&self) -> Option { + let guard = epoch::pin(); + loop { + let head = self.head.load(Acquire, &guard); + + match unsafe { head.as_ref() } { + Some(h) => { + let next = h.next.load(Relaxed, &guard); + + if self + .head + .compare_and_set(head, next, Relaxed, &guard) + .is_ok() + { + unsafe { + guard.defer_destroy(head); + return Some(ManuallyDrop::into_inner(ptr::read(&(*h).data))); + } + } + } + None => return None, + } + } + } + + /// Returns `true` if the stack is empty. + pub fn is_empty(&self) -> bool { + let guard = epoch::pin(); + self.head.load(Acquire, &guard).is_null() + } +} + +impl Drop for TreiberStack { + fn drop(&mut self) { + while self.pop().is_some() {} + } +} + +fn main() { + let stack = TreiberStack::new(); + + scope(|scope| { + for _ in 0..10 { + scope.spawn(|_| { + for i in 0..10_000 { + stack.push(i); + assert!(stack.pop().is_some()); + } + }); + } + }) + .unwrap(); + + assert!(stack.pop().is_none()); +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/atomic.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/atomic.rs new file mode 100644 index 0000000..5177187 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/atomic.rs @@ -0,0 +1,1374 @@ +use core::borrow::{Borrow, BorrowMut}; +use core::cmp; +use core::fmt; +use core::marker::PhantomData; +use core::mem::{self, MaybeUninit}; +use core::ops::{Deref, DerefMut}; +use core::slice; +use core::sync::atomic::{AtomicUsize, Ordering}; + +use crate::alloc::alloc; +use crate::alloc::boxed::Box; +use crate::guard::Guard; +use const_fn::const_fn; +use crossbeam_utils::atomic::AtomicConsume; + +/// Given ordering for the success case in a compare-exchange operation, returns the strongest +/// appropriate ordering for the failure case. +#[inline] +fn strongest_failure_ordering(ord: Ordering) -> Ordering { + use self::Ordering::*; + match ord { + Relaxed | Release => Relaxed, + Acquire | AcqRel => Acquire, + _ => SeqCst, + } +} + +/// The error returned on failed compare-and-set operation. +pub struct CompareAndSetError<'g, T: ?Sized + Pointable, P: Pointer> { + /// The value in the atomic pointer at the time of the failed operation. + pub current: Shared<'g, T>, + + /// The new value, which the operation failed to store. + pub new: P, +} + +impl<'g, T: 'g, P: Pointer + fmt::Debug> fmt::Debug for CompareAndSetError<'g, T, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CompareAndSetError") + .field("current", &self.current) + .field("new", &self.new) + .finish() + } +} + +/// Memory orderings for compare-and-set operations. +/// +/// A compare-and-set operation can have different memory orderings depending on whether it +/// succeeds or fails. This trait generalizes different ways of specifying memory orderings. +/// +/// The two ways of specifying orderings for compare-and-set are: +/// +/// 1. Just one `Ordering` for the success case. In case of failure, the strongest appropriate +/// ordering is chosen. +/// 2. A pair of `Ordering`s. The first one is for the success case, while the second one is +/// for the failure case. +pub trait CompareAndSetOrdering { + /// The ordering of the operation when it succeeds. + fn success(&self) -> Ordering; + + /// The ordering of the operation when it fails. + /// + /// The failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than + /// the success ordering. + fn failure(&self) -> Ordering; +} + +impl CompareAndSetOrdering for Ordering { + #[inline] + fn success(&self) -> Ordering { + *self + } + + #[inline] + fn failure(&self) -> Ordering { + strongest_failure_ordering(*self) + } +} + +impl CompareAndSetOrdering for (Ordering, Ordering) { + #[inline] + fn success(&self) -> Ordering { + self.0 + } + + #[inline] + fn failure(&self) -> Ordering { + self.1 + } +} + +/// Returns a bitmask containing the unused least significant bits of an aligned pointer to `T`. +#[inline] +fn low_bits() -> usize { + (1 << T::ALIGN.trailing_zeros()) - 1 +} + +/// Panics if the pointer is not properly unaligned. +#[inline] +fn ensure_aligned(raw: usize) { + assert_eq!(raw & low_bits::(), 0, "unaligned pointer"); +} + +/// Given a tagged pointer `data`, returns the same pointer, but tagged with `tag`. +/// +/// `tag` is truncated to fit into the unused bits of the pointer to `T`. +#[inline] +fn compose_tag(data: usize, tag: usize) -> usize { + (data & !low_bits::()) | (tag & low_bits::()) +} + +/// Decomposes a tagged pointer `data` into the pointer and the tag. +#[inline] +fn decompose_tag(data: usize) -> (usize, usize) { + (data & !low_bits::(), data & low_bits::()) +} + +/// Types that are pointed to by a single word. +/// +/// In concurrent programming, it is necessary to represent an object within a word because atomic +/// operations (e.g., reads, writes, read-modify-writes) support only single words. This trait +/// qualifies such types that are pointed to by a single word. +/// +/// The trait generalizes `Box` for a sized type `T`. In a box, an object of type `T` is +/// allocated in heap and it is owned by a single-word pointer. This trait is also implemented for +/// `[MaybeUninit]` by storing its size along with its elements and pointing to the pair of array +/// size and elements. +/// +/// Pointers to `Pointable` types can be stored in [`Atomic`], [`Owned`], and [`Shared`]. In +/// particular, Crossbeam supports dynamically sized slices as follows. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// use crossbeam_epoch::Owned; +/// +/// let o = Owned::<[MaybeUninit]>::init(10); // allocating [i32; 10] +/// ``` +pub trait Pointable { + /// The alignment of pointer. + const ALIGN: usize; + + /// The type for initializers. + type Init; + + /// Initializes a with the given initializer. + /// + /// # Safety + /// + /// The result should be a multiple of `ALIGN`. + unsafe fn init(init: Self::Init) -> usize; + + /// Dereferences the given pointer. + /// + /// # Safety + /// + /// - The given `ptr` should have been initialized with [`Pointable::init`]. + /// - `ptr` should not have yet been dropped by [`Pointable::drop`]. + /// - `ptr` should not be mutably dereferenced by [`Pointable::deref_mut`] concurrently. + unsafe fn deref<'a>(ptr: usize) -> &'a Self; + + /// Mutably dereferences the given pointer. + /// + /// # Safety + /// + /// - The given `ptr` should have been initialized with [`Pointable::init`]. + /// - `ptr` should not have yet been dropped by [`Pointable::drop`]. + /// - `ptr` should not be dereferenced by [`Pointable::deref`] or [`Pointable::deref_mut`] + /// concurrently. + unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut Self; + + /// Drops the object pointed to by the given pointer. + /// + /// # Safety + /// + /// - The given `ptr` should have been initialized with [`Pointable::init`]. + /// - `ptr` should not have yet been dropped by [`Pointable::drop`]. + /// - `ptr` should not be dereferenced by [`Pointable::deref`] or [`Pointable::deref_mut`] + /// concurrently. + unsafe fn drop(ptr: usize); +} + +impl Pointable for T { + const ALIGN: usize = mem::align_of::(); + + type Init = T; + + unsafe fn init(init: Self::Init) -> usize { + Box::into_raw(Box::new(init)) as usize + } + + unsafe fn deref<'a>(ptr: usize) -> &'a Self { + &*(ptr as *const T) + } + + unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut Self { + &mut *(ptr as *mut T) + } + + unsafe fn drop(ptr: usize) { + drop(Box::from_raw(ptr as *mut T)); + } +} + +/// Array with size. +/// +/// # Memory layout +/// +/// An array consisting of size and elements: +/// +/// ```text +/// elements +/// | +/// | +/// ------------------------------------ +/// | size | 0 | 1 | 2 | 3 | 4 | 5 | 6 | +/// ------------------------------------ +/// ``` +/// +/// Its memory layout is different from that of `Box<[T]>` in that size is in the allocation (not +/// along with pointer as in `Box<[T]>`). +/// +/// Elements are not present in the type, but they will be in the allocation. +/// ``` +/// +// TODO(@jeehoonkang): once we bump the minimum required Rust version to 1.44 or newer, use +// [`alloc::alloc::Layout::extend`] instead. +#[repr(C)] +struct Array { + size: usize, + elements: [MaybeUninit; 0], +} + +impl Pointable for [MaybeUninit] { + const ALIGN: usize = mem::align_of::>(); + + type Init = usize; + + unsafe fn init(size: Self::Init) -> usize { + let size = mem::size_of::>() + mem::size_of::>() * size; + let align = mem::align_of::>(); + let layout = alloc::Layout::from_size_align(size, align).unwrap(); + let ptr = alloc::alloc(layout) as *mut Array; + (*ptr).size = size; + ptr as usize + } + + unsafe fn deref<'a>(ptr: usize) -> &'a Self { + let array = &*(ptr as *const Array); + slice::from_raw_parts(array.elements.as_ptr() as *const _, array.size) + } + + unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut Self { + let array = &*(ptr as *mut Array); + slice::from_raw_parts_mut(array.elements.as_ptr() as *mut _, array.size) + } + + unsafe fn drop(ptr: usize) { + let array = &*(ptr as *mut Array); + let size = mem::size_of::>() + mem::size_of::>() * array.size; + let align = mem::align_of::>(); + let layout = alloc::Layout::from_size_align(size, align).unwrap(); + alloc::dealloc(ptr as *mut u8, layout); + } +} + +/// An atomic pointer that can be safely shared between threads. +/// +/// The pointer must be properly aligned. Since it is aligned, a tag can be stored into the unused +/// least significant bits of the address. For example, the tag for a pointer to a sized type `T` +/// should be less than `(1 << mem::align_of::().trailing_zeros())`. +/// +/// Any method that loads the pointer must be passed a reference to a [`Guard`]. +/// +/// Crossbeam supports dynamically sized types. See [`Pointable`] for details. +pub struct Atomic { + data: AtomicUsize, + _marker: PhantomData<*mut T>, +} + +unsafe impl Send for Atomic {} +unsafe impl Sync for Atomic {} + +impl Atomic { + /// Allocates `value` on the heap and returns a new atomic pointer pointing to it. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Atomic; + /// + /// let a = Atomic::new(1234); + /// ``` + pub fn new(init: T) -> Atomic { + Self::init(init) + } +} + +impl Atomic { + /// Allocates `value` on the heap and returns a new atomic pointer pointing to it. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Atomic; + /// + /// let a = Atomic::::init(1234); + /// ``` + pub fn init(init: T::Init) -> Atomic { + Self::from(Owned::init(init)) + } + + /// Returns a new atomic pointer pointing to the tagged pointer `data`. + fn from_usize(data: usize) -> Self { + Self { + data: AtomicUsize::new(data), + _marker: PhantomData, + } + } + + /// Returns a new null atomic pointer. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Atomic; + /// + /// let a = Atomic::::null(); + /// ``` + /// + #[const_fn(feature = "nightly")] + pub const fn null() -> Atomic { + Self { + data: AtomicUsize::new(0), + _marker: PhantomData, + } + } + + /// Loads a `Shared` from the atomic pointer. + /// + /// This method takes an [`Ordering`] argument which describes the memory ordering of this + /// operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// let guard = &epoch::pin(); + /// let p = a.load(SeqCst, guard); + /// ``` + pub fn load<'g>(&self, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.data.load(ord)) } + } + + /// Loads a `Shared` from the atomic pointer using a "consume" memory ordering. + /// + /// This is similar to the "acquire" ordering, except that an ordering is + /// only guaranteed with operations that "depend on" the result of the load. + /// However consume loads are usually much faster than acquire loads on + /// architectures with a weak memory model since they don't require memory + /// fence instructions. + /// + /// The exact definition of "depend on" is a bit vague, but it works as you + /// would expect in practice since a lot of software, especially the Linux + /// kernel, rely on this behavior. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// + /// let a = Atomic::new(1234); + /// let guard = &epoch::pin(); + /// let p = a.load_consume(guard); + /// ``` + pub fn load_consume<'g>(&self, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.data.load_consume()) } + } + + /// Stores a `Shared` or `Owned` pointer into the atomic pointer. + /// + /// This method takes an [`Ordering`] argument which describes the memory ordering of this + /// operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{Atomic, Owned, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// a.store(Shared::null(), SeqCst); + /// a.store(Owned::new(1234), SeqCst); + /// ``` + pub fn store>(&self, new: P, ord: Ordering) { + self.data.store(new.into_usize(), ord); + } + + /// Stores a `Shared` or `Owned` pointer into the atomic pointer, returning the previous + /// `Shared`. + /// + /// This method takes an [`Ordering`] argument which describes the memory ordering of this + /// operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// let guard = &epoch::pin(); + /// let p = a.swap(Shared::null(), SeqCst, guard); + /// ``` + pub fn swap<'g, P: Pointer>(&self, new: P, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.data.swap(new.into_usize(), ord)) } + } + + /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current + /// value is the same as `current`. The tag is also taken into account, so two pointers to the + /// same object, but with different tags, will not be considered equal. + /// + /// The return value is a result indicating whether the new pointer was written. On success the + /// pointer that was written is returned. On failure the actual current value and `new` are + /// returned. + /// + /// This method takes a [`CompareAndSetOrdering`] argument which describes the memory + /// ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// + /// let guard = &epoch::pin(); + /// let curr = a.load(SeqCst, guard); + /// let res1 = a.compare_and_set(curr, Shared::null(), SeqCst, guard); + /// let res2 = a.compare_and_set(curr, Owned::new(5678), SeqCst, guard); + /// ``` + pub fn compare_and_set<'g, O, P>( + &self, + current: Shared<'_, T>, + new: P, + ord: O, + _: &'g Guard, + ) -> Result, CompareAndSetError<'g, T, P>> + where + O: CompareAndSetOrdering, + P: Pointer, + { + let new = new.into_usize(); + self.data + .compare_exchange(current.into_usize(), new, ord.success(), ord.failure()) + .map(|_| unsafe { Shared::from_usize(new) }) + .map_err(|current| unsafe { + CompareAndSetError { + current: Shared::from_usize(current), + new: P::from_usize(new), + } + }) + } + + /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current + /// value is the same as `current`. The tag is also taken into account, so two pointers to the + /// same object, but with different tags, will not be considered equal. + /// + /// Unlike [`compare_and_set`], this method is allowed to spuriously fail even when comparison + /// succeeds, which can result in more efficient code on some platforms. The return value is a + /// result indicating whether the new pointer was written. On success the pointer that was + /// written is returned. On failure the actual current value and `new` are returned. + /// + /// This method takes a [`CompareAndSetOrdering`] argument which describes the memory + /// ordering of this operation. + /// + /// [`compare_and_set`]: Atomic::compare_and_set + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// let guard = &epoch::pin(); + /// + /// let mut new = Owned::new(5678); + /// let mut ptr = a.load(SeqCst, guard); + /// loop { + /// match a.compare_and_set_weak(ptr, new, SeqCst, guard) { + /// Ok(p) => { + /// ptr = p; + /// break; + /// } + /// Err(err) => { + /// ptr = err.current; + /// new = err.new; + /// } + /// } + /// } + /// + /// let mut curr = a.load(SeqCst, guard); + /// loop { + /// match a.compare_and_set_weak(curr, Shared::null(), SeqCst, guard) { + /// Ok(_) => break, + /// Err(err) => curr = err.current, + /// } + /// } + /// ``` + pub fn compare_and_set_weak<'g, O, P>( + &self, + current: Shared<'_, T>, + new: P, + ord: O, + _: &'g Guard, + ) -> Result, CompareAndSetError<'g, T, P>> + where + O: CompareAndSetOrdering, + P: Pointer, + { + let new = new.into_usize(); + self.data + .compare_exchange_weak(current.into_usize(), new, ord.success(), ord.failure()) + .map(|_| unsafe { Shared::from_usize(new) }) + .map_err(|current| unsafe { + CompareAndSetError { + current: Shared::from_usize(current), + new: P::from_usize(new), + } + }) + } + + /// Bitwise "and" with the current tag. + /// + /// Performs a bitwise "and" operation on the current tag and the argument `val`, and sets the + /// new tag to the result. Returns the previous pointer. + /// + /// This method takes an [`Ordering`] argument which describes the memory ordering of this + /// operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::::from(Shared::null().with_tag(3)); + /// let guard = &epoch::pin(); + /// assert_eq!(a.fetch_and(2, SeqCst, guard).tag(), 3); + /// assert_eq!(a.load(SeqCst, guard).tag(), 2); + /// ``` + pub fn fetch_and<'g>(&self, val: usize, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.data.fetch_and(val | !low_bits::(), ord)) } + } + + /// Bitwise "or" with the current tag. + /// + /// Performs a bitwise "or" operation on the current tag and the argument `val`, and sets the + /// new tag to the result. Returns the previous pointer. + /// + /// This method takes an [`Ordering`] argument which describes the memory ordering of this + /// operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::::from(Shared::null().with_tag(1)); + /// let guard = &epoch::pin(); + /// assert_eq!(a.fetch_or(2, SeqCst, guard).tag(), 1); + /// assert_eq!(a.load(SeqCst, guard).tag(), 3); + /// ``` + pub fn fetch_or<'g>(&self, val: usize, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.data.fetch_or(val & low_bits::(), ord)) } + } + + /// Bitwise "xor" with the current tag. + /// + /// Performs a bitwise "xor" operation on the current tag and the argument `val`, and sets the + /// new tag to the result. Returns the previous pointer. + /// + /// This method takes an [`Ordering`] argument which describes the memory ordering of this + /// operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::::from(Shared::null().with_tag(1)); + /// let guard = &epoch::pin(); + /// assert_eq!(a.fetch_xor(3, SeqCst, guard).tag(), 1); + /// assert_eq!(a.load(SeqCst, guard).tag(), 2); + /// ``` + pub fn fetch_xor<'g>(&self, val: usize, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.data.fetch_xor(val & low_bits::(), ord)) } + } + + /// Takes ownership of the pointee. + /// + /// This consumes the atomic and converts it into [`Owned`]. As [`Atomic`] doesn't have a + /// destructor and doesn't drop the pointee while [`Owned`] does, this is suitable for + /// destructors of data structures. + /// + /// # Panics + /// + /// Panics if this pointer is null, but only in debug mode. + /// + /// # Safety + /// + /// This method may be called only if the pointer is valid and nobody else is holding a + /// reference to the same object. + /// + /// # Examples + /// + /// ```rust + /// # use std::mem; + /// # use crossbeam_epoch::Atomic; + /// struct DataStructure { + /// ptr: Atomic, + /// } + /// + /// impl Drop for DataStructure { + /// fn drop(&mut self) { + /// // By now the DataStructure lives only in our thread and we are sure we don't hold + /// // any Shared or & to it ourselves. + /// unsafe { + /// drop(mem::replace(&mut self.ptr, Atomic::null()).into_owned()); + /// } + /// } + /// } + /// ``` + pub unsafe fn into_owned(self) -> Owned { + Owned::from_usize(self.data.into_inner()) + } +} + +impl fmt::Debug for Atomic { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data = self.data.load(Ordering::SeqCst); + let (raw, tag) = decompose_tag::(data); + + f.debug_struct("Atomic") + .field("raw", &raw) + .field("tag", &tag) + .finish() + } +} + +impl fmt::Pointer for Atomic { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data = self.data.load(Ordering::SeqCst); + let (raw, _) = decompose_tag::(data); + fmt::Pointer::fmt(&(unsafe { T::deref(raw) as *const _ }), f) + } +} + +impl Clone for Atomic { + /// Returns a copy of the atomic value. + /// + /// Note that a `Relaxed` load is used here. If you need synchronization, use it with other + /// atomics or fences. + fn clone(&self) -> Self { + let data = self.data.load(Ordering::Relaxed); + Atomic::from_usize(data) + } +} + +impl Default for Atomic { + fn default() -> Self { + Atomic::null() + } +} + +impl From> for Atomic { + /// Returns a new atomic pointer pointing to `owned`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{Atomic, Owned}; + /// + /// let a = Atomic::::from(Owned::new(1234)); + /// ``` + fn from(owned: Owned) -> Self { + let data = owned.data; + mem::forget(owned); + Self::from_usize(data) + } +} + +impl From> for Atomic { + fn from(b: Box) -> Self { + Self::from(Owned::from(b)) + } +} + +impl From for Atomic { + fn from(t: T) -> Self { + Self::new(t) + } +} + +impl<'g, T: ?Sized + Pointable> From> for Atomic { + /// Returns a new atomic pointer pointing to `ptr`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{Atomic, Shared}; + /// + /// let a = Atomic::::from(Shared::::null()); + /// ``` + fn from(ptr: Shared<'g, T>) -> Self { + Self::from_usize(ptr.data) + } +} + +impl From<*const T> for Atomic { + /// Returns a new atomic pointer pointing to `raw`. + /// + /// # Examples + /// + /// ``` + /// use std::ptr; + /// use crossbeam_epoch::Atomic; + /// + /// let a = Atomic::::from(ptr::null::()); + /// ``` + fn from(raw: *const T) -> Self { + Self::from_usize(raw as usize) + } +} + +/// A trait for either `Owned` or `Shared` pointers. +pub trait Pointer { + /// Returns the machine representation of the pointer. + fn into_usize(self) -> usize; + + /// Returns a new pointer pointing to the tagged pointer `data`. + /// + /// # Safety + /// + /// The given `data` should have been created by `Pointer::into_usize()`, and one `data` should + /// not be converted back by `Pointer::from_usize()` multiple times. + unsafe fn from_usize(data: usize) -> Self; +} + +/// An owned heap-allocated object. +/// +/// This type is very similar to `Box`. +/// +/// The pointer must be properly aligned. Since it is aligned, a tag can be stored into the unused +/// least significant bits of the address. +pub struct Owned { + data: usize, + _marker: PhantomData>, +} + +impl Pointer for Owned { + #[inline] + fn into_usize(self) -> usize { + let data = self.data; + mem::forget(self); + data + } + + /// Returns a new pointer pointing to the tagged pointer `data`. + /// + /// # Panics + /// + /// Panics if the data is zero in debug mode. + #[inline] + unsafe fn from_usize(data: usize) -> Self { + debug_assert!(data != 0, "converting zero into `Owned`"); + Owned { + data, + _marker: PhantomData, + } + } +} + +impl Owned { + /// Returns a new owned pointer pointing to `raw`. + /// + /// This function is unsafe because improper use may lead to memory problems. Argument `raw` + /// must be a valid pointer. Also, a double-free may occur if the function is called twice on + /// the same raw pointer. + /// + /// # Panics + /// + /// Panics if `raw` is not properly aligned. + /// + /// # Safety + /// + /// The given `raw` should have been derived from `Owned`, and one `raw` should not be converted + /// back by `Owned::from_raw()` multiple times. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// let o = unsafe { Owned::from_raw(Box::into_raw(Box::new(1234))) }; + /// ``` + pub unsafe fn from_raw(raw: *mut T) -> Owned { + let raw = raw as usize; + ensure_aligned::(raw); + Self::from_usize(raw) + } + + /// Converts the owned pointer into a `Box`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// let o = Owned::new(1234); + /// let b: Box = o.into_box(); + /// assert_eq!(*b, 1234); + /// ``` + pub fn into_box(self) -> Box { + let (raw, _) = decompose_tag::(self.data); + mem::forget(self); + unsafe { Box::from_raw(raw as *mut _) } + } + + /// Allocates `value` on the heap and returns a new owned pointer pointing to it. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// let o = Owned::new(1234); + /// ``` + pub fn new(init: T) -> Owned { + Self::init(init) + } +} + +impl Owned { + /// Allocates `value` on the heap and returns a new owned pointer pointing to it. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// let o = Owned::::init(1234); + /// ``` + pub fn init(init: T::Init) -> Owned { + unsafe { Self::from_usize(T::init(init)) } + } + + /// Converts the owned pointer into a [`Shared`]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Owned}; + /// + /// let o = Owned::new(1234); + /// let guard = &epoch::pin(); + /// let p = o.into_shared(guard); + /// ``` + #[allow(clippy::needless_lifetimes)] + pub fn into_shared<'g>(self, _: &'g Guard) -> Shared<'g, T> { + unsafe { Shared::from_usize(self.into_usize()) } + } + + /// Returns the tag stored within the pointer. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// assert_eq!(Owned::new(1234).tag(), 0); + /// ``` + pub fn tag(&self) -> usize { + let (_, tag) = decompose_tag::(self.data); + tag + } + + /// Returns the same pointer, but tagged with `tag`. `tag` is truncated to be fit into the + /// unused bits of the pointer to `T`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// let o = Owned::new(0u64); + /// assert_eq!(o.tag(), 0); + /// let o = o.with_tag(2); + /// assert_eq!(o.tag(), 2); + /// ``` + pub fn with_tag(self, tag: usize) -> Owned { + let data = self.into_usize(); + unsafe { Self::from_usize(compose_tag::(data, tag)) } + } +} + +impl Drop for Owned { + fn drop(&mut self) { + let (raw, _) = decompose_tag::(self.data); + unsafe { + T::drop(raw); + } + } +} + +impl fmt::Debug for Owned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (raw, tag) = decompose_tag::(self.data); + + f.debug_struct("Owned") + .field("raw", &raw) + .field("tag", &tag) + .finish() + } +} + +impl Clone for Owned { + fn clone(&self) -> Self { + Owned::new((**self).clone()).with_tag(self.tag()) + } +} + +impl Deref for Owned { + type Target = T; + + fn deref(&self) -> &T { + let (raw, _) = decompose_tag::(self.data); + unsafe { T::deref(raw) } + } +} + +impl DerefMut for Owned { + fn deref_mut(&mut self) -> &mut T { + let (raw, _) = decompose_tag::(self.data); + unsafe { T::deref_mut(raw) } + } +} + +impl From for Owned { + fn from(t: T) -> Self { + Owned::new(t) + } +} + +impl From> for Owned { + /// Returns a new owned pointer pointing to `b`. + /// + /// # Panics + /// + /// Panics if the pointer (the `Box`) is not properly aligned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Owned; + /// + /// let o = unsafe { Owned::from_raw(Box::into_raw(Box::new(1234))) }; + /// ``` + fn from(b: Box) -> Self { + unsafe { Self::from_raw(Box::into_raw(b)) } + } +} + +impl Borrow for Owned { + fn borrow(&self) -> &T { + self.deref() + } +} + +impl BorrowMut for Owned { + fn borrow_mut(&mut self) -> &mut T { + self.deref_mut() + } +} + +impl AsRef for Owned { + fn as_ref(&self) -> &T { + self.deref() + } +} + +impl AsMut for Owned { + fn as_mut(&mut self) -> &mut T { + self.deref_mut() + } +} + +/// A pointer to an object protected by the epoch GC. +/// +/// The pointer is valid for use only during the lifetime `'g`. +/// +/// The pointer must be properly aligned. Since it is aligned, a tag can be stored into the unused +/// least significant bits of the address. +pub struct Shared<'g, T: 'g + ?Sized + Pointable> { + data: usize, + _marker: PhantomData<(&'g (), *const T)>, +} + +impl Clone for Shared<'_, T> { + fn clone(&self) -> Self { + Self { + data: self.data, + _marker: PhantomData, + } + } +} + +impl Copy for Shared<'_, T> {} + +impl Pointer for Shared<'_, T> { + #[inline] + fn into_usize(self) -> usize { + self.data + } + + #[inline] + unsafe fn from_usize(data: usize) -> Self { + Shared { + data, + _marker: PhantomData, + } + } +} + +impl<'g, T> Shared<'g, T> { + /// Converts the pointer to a raw pointer (without the tag). + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let o = Owned::new(1234); + /// let raw = &*o as *const _; + /// let a = Atomic::from(o); + /// + /// let guard = &epoch::pin(); + /// let p = a.load(SeqCst, guard); + /// assert_eq!(p.as_raw(), raw); + /// ``` + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn as_raw(&self) -> *const T { + let (raw, _) = decompose_tag::(self.data); + raw as *const _ + } +} + +impl<'g, T: ?Sized + Pointable> Shared<'g, T> { + /// Returns a new null pointer. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Shared; + /// + /// let p = Shared::::null(); + /// assert!(p.is_null()); + /// ``` + pub fn null() -> Shared<'g, T> { + Shared { + data: 0, + _marker: PhantomData, + } + } + + /// Returns `true` if the pointer is null. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::null(); + /// let guard = &epoch::pin(); + /// assert!(a.load(SeqCst, guard).is_null()); + /// a.store(Owned::new(1234), SeqCst); + /// assert!(!a.load(SeqCst, guard).is_null()); + /// ``` + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn is_null(&self) -> bool { + let (raw, _) = decompose_tag::(self.data); + raw == 0 + } + + /// Dereferences the pointer. + /// + /// Returns a reference to the pointee that is valid during the lifetime `'g`. + /// + /// # Safety + /// + /// Dereferencing a pointer is unsafe because it could be pointing to invalid memory. + /// + /// Another concern is the possibility of data races due to lack of proper synchronization. + /// For example, consider the following scenario: + /// + /// 1. A thread creates a new object: `a.store(Owned::new(10), Relaxed)` + /// 2. Another thread reads it: `*a.load(Relaxed, guard).as_ref().unwrap()` + /// + /// The problem is that relaxed orderings don't synchronize initialization of the object with + /// the read from the second thread. This is a data race. A possible solution would be to use + /// `Release` and `Acquire` orderings. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// let guard = &epoch::pin(); + /// let p = a.load(SeqCst, guard); + /// unsafe { + /// assert_eq!(p.deref(), &1234); + /// } + /// ``` + #[allow(clippy::trivially_copy_pass_by_ref)] + #[allow(clippy::should_implement_trait)] + pub unsafe fn deref(&self) -> &'g T { + let (raw, _) = decompose_tag::(self.data); + T::deref(raw) + } + + /// Dereferences the pointer. + /// + /// Returns a mutable reference to the pointee that is valid during the lifetime `'g`. + /// + /// # Safety + /// + /// * There is no guarantee that there are no more threads attempting to read/write from/to the + /// actual object at the same time. + /// + /// The user must know that there are no concurrent accesses towards the object itself. + /// + /// * Other than the above, all safety concerns of `deref()` applies here. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(vec![1, 2, 3, 4]); + /// let guard = &epoch::pin(); + /// + /// let mut p = a.load(SeqCst, guard); + /// unsafe { + /// assert!(!p.is_null()); + /// let b = p.deref_mut(); + /// assert_eq!(b, &vec![1, 2, 3, 4]); + /// b.push(5); + /// assert_eq!(b, &vec![1, 2, 3, 4, 5]); + /// } + /// + /// let p = a.load(SeqCst, guard); + /// unsafe { + /// assert_eq!(p.deref(), &vec![1, 2, 3, 4, 5]); + /// } + /// ``` + #[allow(clippy::should_implement_trait)] + pub unsafe fn deref_mut(&mut self) -> &'g mut T { + let (raw, _) = decompose_tag::(self.data); + T::deref_mut(raw) + } + + /// Converts the pointer to a reference. + /// + /// Returns `None` if the pointer is null, or else a reference to the object wrapped in `Some`. + /// + /// # Safety + /// + /// Dereferencing a pointer is unsafe because it could be pointing to invalid memory. + /// + /// Another concern is the possibility of data races due to lack of proper synchronization. + /// For example, consider the following scenario: + /// + /// 1. A thread creates a new object: `a.store(Owned::new(10), Relaxed)` + /// 2. Another thread reads it: `*a.load(Relaxed, guard).as_ref().unwrap()` + /// + /// The problem is that relaxed orderings don't synchronize initialization of the object with + /// the read from the second thread. This is a data race. A possible solution would be to use + /// `Release` and `Acquire` orderings. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// let guard = &epoch::pin(); + /// let p = a.load(SeqCst, guard); + /// unsafe { + /// assert_eq!(p.as_ref(), Some(&1234)); + /// } + /// ``` + #[allow(clippy::trivially_copy_pass_by_ref)] + pub unsafe fn as_ref(&self) -> Option<&'g T> { + let (raw, _) = decompose_tag::(self.data); + if raw == 0 { + None + } else { + Some(T::deref(raw)) + } + } + + /// Takes ownership of the pointee. + /// + /// # Panics + /// + /// Panics if this pointer is null, but only in debug mode. + /// + /// # Safety + /// + /// This method may be called only if the pointer is valid and nobody else is holding a + /// reference to the same object. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(1234); + /// unsafe { + /// let guard = &epoch::unprotected(); + /// let p = a.load(SeqCst, guard); + /// drop(p.into_owned()); + /// } + /// ``` + pub unsafe fn into_owned(self) -> Owned { + debug_assert!(!self.is_null(), "converting a null `Shared` into `Owned`"); + Owned::from_usize(self.data) + } + + /// Returns the tag stored within the pointer. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::::from(Owned::new(0u64).with_tag(2)); + /// let guard = &epoch::pin(); + /// let p = a.load(SeqCst, guard); + /// assert_eq!(p.tag(), 2); + /// ``` + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn tag(&self) -> usize { + let (_, tag) = decompose_tag::(self.data); + tag + } + + /// Returns the same pointer, but tagged with `tag`. `tag` is truncated to be fit into the + /// unused bits of the pointer to `T`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(0u64); + /// let guard = &epoch::pin(); + /// let p1 = a.load(SeqCst, guard); + /// let p2 = p1.with_tag(2); + /// + /// assert_eq!(p1.tag(), 0); + /// assert_eq!(p2.tag(), 2); + /// assert_eq!(p1.as_raw(), p2.as_raw()); + /// ``` + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn with_tag(&self, tag: usize) -> Shared<'g, T> { + unsafe { Self::from_usize(compose_tag::(self.data, tag)) } + } +} + +impl From<*const T> for Shared<'_, T> { + /// Returns a new pointer pointing to `raw`. + /// + /// # Panics + /// + /// Panics if `raw` is not properly aligned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::Shared; + /// + /// let p = Shared::from(Box::into_raw(Box::new(1234)) as *const _); + /// assert!(!p.is_null()); + /// ``` + fn from(raw: *const T) -> Self { + let raw = raw as usize; + ensure_aligned::(raw); + unsafe { Self::from_usize(raw) } + } +} + +impl<'g, T: ?Sized + Pointable> PartialEq> for Shared<'g, T> { + fn eq(&self, other: &Self) -> bool { + self.data == other.data + } +} + +impl Eq for Shared<'_, T> {} + +impl<'g, T: ?Sized + Pointable> PartialOrd> for Shared<'g, T> { + fn partial_cmp(&self, other: &Self) -> Option { + self.data.partial_cmp(&other.data) + } +} + +impl Ord for Shared<'_, T> { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.data.cmp(&other.data) + } +} + +impl fmt::Debug for Shared<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (raw, tag) = decompose_tag::(self.data); + + f.debug_struct("Shared") + .field("raw", &raw) + .field("tag", &tag) + .finish() + } +} + +impl fmt::Pointer for Shared<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(unsafe { self.deref() as *const _ }), f) + } +} + +impl Default for Shared<'_, T> { + fn default() -> Self { + Shared::null() + } +} + +#[cfg(test)] +mod tests { + use super::Shared; + + #[test] + fn valid_tag_i8() { + Shared::::null().with_tag(0); + } + + #[test] + fn valid_tag_i64() { + Shared::::null().with_tag(7); + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/collector.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/collector.rs new file mode 100644 index 0000000..8224e11 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/collector.rs @@ -0,0 +1,440 @@ +/// Epoch-based garbage collector. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_epoch::Collector; +/// +/// let collector = Collector::new(); +/// +/// let handle = collector.register(); +/// drop(collector); // `handle` still works after dropping `collector` +/// +/// handle.pin().flush(); +/// ``` +use core::fmt; + +use crate::alloc::sync::Arc; +use crate::guard::Guard; +use crate::internal::{Global, Local}; + +/// An epoch-based garbage collector. +pub struct Collector { + pub(crate) global: Arc, +} + +unsafe impl Send for Collector {} +unsafe impl Sync for Collector {} + +impl Default for Collector { + fn default() -> Self { + Self { + global: Arc::new(Global::new()), + } + } +} + +impl Collector { + /// Creates a new collector. + pub fn new() -> Self { + Self::default() + } + + /// Registers a new handle for the collector. + pub fn register(&self) -> LocalHandle { + Local::register(self) + } +} + +impl Clone for Collector { + /// Creates another reference to the same garbage collector. + fn clone(&self) -> Self { + Collector { + global: self.global.clone(), + } + } +} + +impl fmt::Debug for Collector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Collector { .. }") + } +} + +impl PartialEq for Collector { + /// Checks if both handles point to the same collector. + fn eq(&self, rhs: &Collector) -> bool { + Arc::ptr_eq(&self.global, &rhs.global) + } +} +impl Eq for Collector {} + +/// A handle to a garbage collector. +pub struct LocalHandle { + pub(crate) local: *const Local, +} + +impl LocalHandle { + /// Pins the handle. + #[inline] + pub fn pin(&self) -> Guard { + unsafe { (*self.local).pin() } + } + + /// Returns `true` if the handle is pinned. + #[inline] + pub fn is_pinned(&self) -> bool { + unsafe { (*self.local).is_pinned() } + } + + /// Returns the `Collector` associated with this handle. + #[inline] + pub fn collector(&self) -> &Collector { + unsafe { (*self.local).collector() } + } +} + +impl Drop for LocalHandle { + #[inline] + fn drop(&mut self) { + unsafe { + Local::release_handle(&*self.local); + } + } +} + +impl fmt::Debug for LocalHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("LocalHandle { .. }") + } +} + +#[cfg(test)] +mod tests { + use std::mem; + use std::sync::atomic::{AtomicUsize, Ordering}; + + use crossbeam_utils::thread; + + use crate::{Collector, Owned}; + + const NUM_THREADS: usize = 8; + + #[test] + fn pin_reentrant() { + let collector = Collector::new(); + let handle = collector.register(); + drop(collector); + + assert!(!handle.is_pinned()); + { + let _guard = &handle.pin(); + assert!(handle.is_pinned()); + { + let _guard = &handle.pin(); + assert!(handle.is_pinned()); + } + assert!(handle.is_pinned()); + } + assert!(!handle.is_pinned()); + } + + #[test] + fn flush_local_bag() { + let collector = Collector::new(); + let handle = collector.register(); + drop(collector); + + for _ in 0..100 { + let guard = &handle.pin(); + unsafe { + let a = Owned::new(7).into_shared(guard); + guard.defer_destroy(a); + + assert!(!(*(*guard.local).bag.get()).is_empty()); + + while !(*(*guard.local).bag.get()).is_empty() { + guard.flush(); + } + } + } + } + + #[test] + fn garbage_buffering() { + let collector = Collector::new(); + let handle = collector.register(); + drop(collector); + + let guard = &handle.pin(); + unsafe { + for _ in 0..10 { + let a = Owned::new(7).into_shared(guard); + guard.defer_destroy(a); + } + assert!(!(*(*guard.local).bag.get()).is_empty()); + } + } + + #[test] + fn pin_holds_advance() { + let collector = Collector::new(); + + thread::scope(|scope| { + for _ in 0..NUM_THREADS { + scope.spawn(|_| { + let handle = collector.register(); + for _ in 0..500_000 { + let guard = &handle.pin(); + + let before = collector.global.epoch.load(Ordering::Relaxed); + collector.global.collect(guard); + let after = collector.global.epoch.load(Ordering::Relaxed); + + assert!(after.wrapping_sub(before) <= 2); + } + }); + } + }) + .unwrap(); + } + + #[test] + fn incremental() { + const COUNT: usize = 100_000; + static DESTROYS: AtomicUsize = AtomicUsize::new(0); + + let collector = Collector::new(); + let handle = collector.register(); + + unsafe { + let guard = &handle.pin(); + for _ in 0..COUNT { + let a = Owned::new(7i32).into_shared(guard); + guard.defer_unchecked(move || { + drop(a.into_owned()); + DESTROYS.fetch_add(1, Ordering::Relaxed); + }); + } + guard.flush(); + } + + let mut last = 0; + + while last < COUNT { + let curr = DESTROYS.load(Ordering::Relaxed); + assert!(curr - last <= 1024); + last = curr; + + let guard = &handle.pin(); + collector.global.collect(guard); + } + assert!(DESTROYS.load(Ordering::Relaxed) == 100_000); + } + + #[test] + fn buffering() { + const COUNT: usize = 10; + static DESTROYS: AtomicUsize = AtomicUsize::new(0); + + let collector = Collector::new(); + let handle = collector.register(); + + unsafe { + let guard = &handle.pin(); + for _ in 0..COUNT { + let a = Owned::new(7i32).into_shared(guard); + guard.defer_unchecked(move || { + drop(a.into_owned()); + DESTROYS.fetch_add(1, Ordering::Relaxed); + }); + } + } + + for _ in 0..100_000 { + collector.global.collect(&handle.pin()); + } + assert!(DESTROYS.load(Ordering::Relaxed) < COUNT); + + handle.pin().flush(); + + while DESTROYS.load(Ordering::Relaxed) < COUNT { + let guard = &handle.pin(); + collector.global.collect(guard); + } + assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT); + } + + #[test] + fn count_drops() { + const COUNT: usize = 100_000; + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct Elem(i32); + + impl Drop for Elem { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::Relaxed); + } + } + + let collector = Collector::new(); + let handle = collector.register(); + + unsafe { + let guard = &handle.pin(); + + for _ in 0..COUNT { + let a = Owned::new(Elem(7i32)).into_shared(guard); + guard.defer_destroy(a); + } + guard.flush(); + } + + while DROPS.load(Ordering::Relaxed) < COUNT { + let guard = &handle.pin(); + collector.global.collect(guard); + } + assert_eq!(DROPS.load(Ordering::Relaxed), COUNT); + } + + #[test] + fn count_destroy() { + const COUNT: usize = 100_000; + static DESTROYS: AtomicUsize = AtomicUsize::new(0); + + let collector = Collector::new(); + let handle = collector.register(); + + unsafe { + let guard = &handle.pin(); + + for _ in 0..COUNT { + let a = Owned::new(7i32).into_shared(guard); + guard.defer_unchecked(move || { + drop(a.into_owned()); + DESTROYS.fetch_add(1, Ordering::Relaxed); + }); + } + guard.flush(); + } + + while DESTROYS.load(Ordering::Relaxed) < COUNT { + let guard = &handle.pin(); + collector.global.collect(guard); + } + assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT); + } + + #[test] + fn drop_array() { + const COUNT: usize = 700; + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct Elem(i32); + + impl Drop for Elem { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::Relaxed); + } + } + + let collector = Collector::new(); + let handle = collector.register(); + + let mut guard = handle.pin(); + + let mut v = Vec::with_capacity(COUNT); + for i in 0..COUNT { + v.push(Elem(i as i32)); + } + + { + let a = Owned::new(v).into_shared(&guard); + unsafe { + guard.defer_destroy(a); + } + guard.flush(); + } + + while DROPS.load(Ordering::Relaxed) < COUNT { + guard.repin(); + collector.global.collect(&guard); + } + assert_eq!(DROPS.load(Ordering::Relaxed), COUNT); + } + + #[test] + fn destroy_array() { + const COUNT: usize = 100_000; + static DESTROYS: AtomicUsize = AtomicUsize::new(0); + + let collector = Collector::new(); + let handle = collector.register(); + + unsafe { + let guard = &handle.pin(); + + let mut v = Vec::with_capacity(COUNT); + for i in 0..COUNT { + v.push(i as i32); + } + + let ptr = v.as_mut_ptr() as usize; + let len = v.len(); + guard.defer_unchecked(move || { + drop(Vec::from_raw_parts(ptr as *const i32 as *mut i32, len, len)); + DESTROYS.fetch_add(len, Ordering::Relaxed); + }); + guard.flush(); + + mem::forget(v); + } + + while DESTROYS.load(Ordering::Relaxed) < COUNT { + let guard = &handle.pin(); + collector.global.collect(guard); + } + assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT); + } + + #[test] + fn stress() { + const THREADS: usize = 8; + const COUNT: usize = 100_000; + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct Elem(i32); + + impl Drop for Elem { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::Relaxed); + } + } + + let collector = Collector::new(); + + thread::scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let handle = collector.register(); + for _ in 0..COUNT { + let guard = &handle.pin(); + unsafe { + let a = Owned::new(Elem(7i32)).into_shared(guard); + guard.defer_destroy(a); + } + } + }); + } + }) + .unwrap(); + + let handle = collector.register(); + while DROPS.load(Ordering::Relaxed) < COUNT * THREADS { + let guard = &handle.pin(); + collector.global.collect(guard); + } + assert_eq!(DROPS.load(Ordering::Relaxed), COUNT * THREADS); + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/default.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/default.rs new file mode 100644 index 0000000..1deac21 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/default.rs @@ -0,0 +1,77 @@ +//! The default garbage collector. +//! +//! For each thread, a participant is lazily initialized on its first use, when the current thread +//! is registered in the default collector. If initialized, the thread's participant will get +//! destructed on thread exit, which in turn unregisters the thread. + +use crate::collector::{Collector, LocalHandle}; +use crate::guard::Guard; +use lazy_static::lazy_static; + +lazy_static! { + /// The global data for the default garbage collector. + static ref COLLECTOR: Collector = Collector::new(); +} + +thread_local! { + /// The per-thread participant for the default garbage collector. + static HANDLE: LocalHandle = COLLECTOR.register(); +} + +/// Pins the current thread. +#[inline] +pub fn pin() -> Guard { + with_handle(|handle| handle.pin()) +} + +/// Returns `true` if the current thread is pinned. +#[inline] +pub fn is_pinned() -> bool { + with_handle(|handle| handle.is_pinned()) +} + +/// Returns the default global collector. +pub fn default_collector() -> &'static Collector { + &COLLECTOR +} + +#[inline] +fn with_handle(mut f: F) -> R +where + F: FnMut(&LocalHandle) -> R, +{ + HANDLE + .try_with(|h| f(h)) + .unwrap_or_else(|_| f(&COLLECTOR.register())) +} + +#[cfg(test)] +mod tests { + use crossbeam_utils::thread; + + #[test] + fn pin_while_exiting() { + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + // Pin after `HANDLE` has been dropped. This must not panic. + super::pin(); + } + } + + thread_local! { + static FOO: Foo = Foo; + } + + thread::scope(|scope| { + scope.spawn(|_| { + // Initialize `FOO` and then `HANDLE`. + FOO.with(|_| ()); + super::pin(); + // At thread exit, `HANDLE` gets dropped first and `FOO` second. + }); + }) + .unwrap(); + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/deferred.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/deferred.rs new file mode 100644 index 0000000..9f4869b --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/deferred.rs @@ -0,0 +1,137 @@ +use alloc::boxed::Box; +use core::fmt; +use core::marker::PhantomData; +use core::mem::{self, MaybeUninit}; +use core::ptr; + +/// Number of words a piece of `Data` can hold. +/// +/// Three words should be enough for the majority of cases. For example, you can fit inside it the +/// function pointer together with a fat pointer representing an object that needs to be destroyed. +const DATA_WORDS: usize = 3; + +/// Some space to keep a `FnOnce()` object on the stack. +type Data = [usize; DATA_WORDS]; + +/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap. +/// +/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure. +pub struct Deferred { + call: unsafe fn(*mut u8), + data: Data, + _marker: PhantomData<*mut ()>, // !Send + !Sync +} + +impl fmt::Debug for Deferred { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.pad("Deferred { .. }") + } +} + +impl Deferred { + /// Constructs a new `Deferred` from a `FnOnce()`. + pub fn new(f: F) -> Self { + let size = mem::size_of::(); + let align = mem::align_of::(); + + unsafe { + if size <= mem::size_of::() && align <= mem::align_of::() { + let mut data = MaybeUninit::::uninit(); + ptr::write(data.as_mut_ptr() as *mut F, f); + + unsafe fn call(raw: *mut u8) { + let f: F = ptr::read(raw as *mut F); + f(); + } + + Deferred { + call: call::, + data: data.assume_init(), + _marker: PhantomData, + } + } else { + let b: Box = Box::new(f); + let mut data = MaybeUninit::::uninit(); + ptr::write(data.as_mut_ptr() as *mut Box, b); + + unsafe fn call(raw: *mut u8) { + // It's safe to cast `raw` from `*mut u8` to `*mut Box`, because `raw` is + // originally derived from `*mut Box`. + #[allow(clippy::cast_ptr_alignment)] + let b: Box = ptr::read(raw as *mut Box); + (*b)(); + } + + Deferred { + call: call::, + data: data.assume_init(), + _marker: PhantomData, + } + } + } + } + + /// Calls the function. + #[inline] + pub fn call(mut self) { + let call = self.call; + unsafe { call(&mut self.data as *mut Data as *mut u8) }; + } +} + +#[cfg(test)] +mod tests { + use super::Deferred; + use std::cell::Cell; + + #[test] + fn on_stack() { + let fired = &Cell::new(false); + let a = [0usize; 1]; + + let d = Deferred::new(move || { + drop(a); + fired.set(true); + }); + + assert!(!fired.get()); + d.call(); + assert!(fired.get()); + } + + #[test] + fn on_heap() { + let fired = &Cell::new(false); + let a = [0usize; 10]; + + let d = Deferred::new(move || { + drop(a); + fired.set(true); + }); + + assert!(!fired.get()); + d.call(); + assert!(fired.get()); + } + + #[test] + fn string() { + let a = "hello".to_string(); + let d = Deferred::new(move || assert_eq!(a, "hello")); + d.call(); + } + + #[test] + fn boxed_slice_i32() { + let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice(); + let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7])); + d.call(); + } + + #[test] + fn long_slice_usize() { + let a: [usize; 5] = [2, 3, 5, 7, 11]; + let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11])); + d.call(); + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/epoch.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/epoch.rs new file mode 100644 index 0000000..e7759d9 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/epoch.rs @@ -0,0 +1,114 @@ +//! The global epoch +//! +//! The last bit in this number is unused and is always zero. Every so often the global epoch is +//! incremented, i.e. we say it "advances". A pinned participant may advance the global epoch only +//! if all currently pinned participants have been pinned in the current epoch. +//! +//! If an object became garbage in some epoch, then we can be sure that after two advancements no +//! participant will hold a reference to it. That is the crux of safe memory reclamation. + +use core::sync::atomic::{AtomicUsize, Ordering}; + +/// An epoch that can be marked as pinned or unpinned. +/// +/// Internally, the epoch is represented as an integer that wraps around at some unspecified point +/// and a flag that represents whether it is pinned or unpinned. +#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] +pub struct Epoch { + /// The least significant bit is set if pinned. The rest of the bits hold the epoch. + data: usize, +} + +impl Epoch { + /// Returns the starting epoch in unpinned state. + #[inline] + pub fn starting() -> Self { + Self::default() + } + + /// Returns the number of epochs `self` is ahead of `rhs`. + /// + /// Internally, epochs are represented as numbers in the range `(isize::MIN / 2) .. (isize::MAX + /// / 2)`, so the returned distance will be in the same interval. + pub fn wrapping_sub(self, rhs: Self) -> isize { + // The result is the same with `(self.data & !1).wrapping_sub(rhs.data & !1) as isize >> 1`, + // because the possible difference of LSB in `(self.data & !1).wrapping_sub(rhs.data & !1)` + // will be ignored in the shift operation. + self.data.wrapping_sub(rhs.data & !1) as isize >> 1 + } + + /// Returns `true` if the epoch is marked as pinned. + #[inline] + pub fn is_pinned(self) -> bool { + (self.data & 1) == 1 + } + + /// Returns the same epoch, but marked as pinned. + #[inline] + pub fn pinned(self) -> Epoch { + Epoch { + data: self.data | 1, + } + } + + /// Returns the same epoch, but marked as unpinned. + #[inline] + pub fn unpinned(self) -> Epoch { + Epoch { + data: self.data & !1, + } + } + + /// Returns the successor epoch. + /// + /// The returned epoch will be marked as pinned only if the previous one was as well. + #[inline] + pub fn successor(self) -> Epoch { + Epoch { + data: self.data.wrapping_add(2), + } + } +} + +/// An atomic value that holds an `Epoch`. +#[derive(Default, Debug)] +pub struct AtomicEpoch { + /// Since `Epoch` is just a wrapper around `usize`, an `AtomicEpoch` is similarly represented + /// using an `AtomicUsize`. + data: AtomicUsize, +} + +impl AtomicEpoch { + /// Creates a new atomic epoch. + #[inline] + pub fn new(epoch: Epoch) -> Self { + let data = AtomicUsize::new(epoch.data); + AtomicEpoch { data } + } + + /// Loads a value from the atomic epoch. + #[inline] + pub fn load(&self, ord: Ordering) -> Epoch { + Epoch { + data: self.data.load(ord), + } + } + + /// Stores a value into the atomic epoch. + #[inline] + pub fn store(&self, epoch: Epoch, ord: Ordering) { + self.data.store(epoch.data, ord); + } + + /// Stores a value into the atomic epoch if the current value is the same as `current`. + /// + /// The return value is always the previous value. If it is equal to `current`, then the value + /// is updated. + /// + /// The `Ordering` argument describes the memory ordering of this operation. + #[inline] + pub fn compare_and_swap(&self, current: Epoch, new: Epoch, ord: Ordering) -> Epoch { + let data = self.data.compare_and_swap(current.data, new.data, ord); + Epoch { data } + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/guard.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/guard.rs new file mode 100644 index 0000000..6db3750 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/guard.rs @@ -0,0 +1,514 @@ +use core::fmt; +use core::mem; + +use scopeguard::defer; + +use crate::atomic::Shared; +use crate::collector::Collector; +use crate::deferred::Deferred; +use crate::internal::Local; + +/// A guard that keeps the current thread pinned. +/// +/// # Pinning +/// +/// The current thread is pinned by calling [`pin`], which returns a new guard: +/// +/// ``` +/// use crossbeam_epoch as epoch; +/// +/// // It is often convenient to prefix a call to `pin` with a `&` in order to create a reference. +/// // This is not really necessary, but makes passing references to the guard a bit easier. +/// let guard = &epoch::pin(); +/// ``` +/// +/// When a guard gets dropped, the current thread is automatically unpinned. +/// +/// # Pointers on the stack +/// +/// Having a guard allows us to create pointers on the stack to heap-allocated objects. +/// For example: +/// +/// ``` +/// use crossbeam_epoch::{self as epoch, Atomic}; +/// use std::sync::atomic::Ordering::SeqCst; +/// +/// // Create a heap-allocated number. +/// let a = Atomic::new(777); +/// +/// // Pin the current thread. +/// let guard = &epoch::pin(); +/// +/// // Load the heap-allocated object and create pointer `p` on the stack. +/// let p = a.load(SeqCst, guard); +/// +/// // Dereference the pointer and print the value: +/// if let Some(num) = unsafe { p.as_ref() } { +/// println!("The number is {}.", num); +/// } +/// ``` +/// +/// # Multiple guards +/// +/// Pinning is reentrant and it is perfectly legal to create multiple guards. In that case, the +/// thread will actually be pinned only when the first guard is created and unpinned when the last +/// one is dropped: +/// +/// ``` +/// use crossbeam_epoch as epoch; +/// +/// let guard1 = epoch::pin(); +/// let guard2 = epoch::pin(); +/// assert!(epoch::is_pinned()); +/// drop(guard1); +/// assert!(epoch::is_pinned()); +/// drop(guard2); +/// assert!(!epoch::is_pinned()); +/// ``` +/// +/// [`pin`]: super::pin +pub struct Guard { + pub(crate) local: *const Local, +} + +impl Guard { + /// Stores a function so that it can be executed at some point after all currently pinned + /// threads get unpinned. + /// + /// This method first stores `f` into the thread-local (or handle-local) cache. If this cache + /// becomes full, some functions are moved into the global cache. At the same time, some + /// functions from both local and global caches may get executed in order to incrementally + /// clean up the caches as they fill up. + /// + /// There is no guarantee when exactly `f` will be executed. The only guarantee is that it + /// won't be executed until all currently pinned threads get unpinned. In theory, `f` might + /// never run, but the epoch-based garbage collection will make an effort to execute it + /// reasonably soon. + /// + /// If this method is called from an [`unprotected`] guard, the function will simply be + /// executed immediately. + pub fn defer(&self, f: F) + where + F: FnOnce() -> R, + F: Send + 'static, + { + unsafe { + self.defer_unchecked(f); + } + } + + /// Stores a function so that it can be executed at some point after all currently pinned + /// threads get unpinned. + /// + /// This method first stores `f` into the thread-local (or handle-local) cache. If this cache + /// becomes full, some functions are moved into the global cache. At the same time, some + /// functions from both local and global caches may get executed in order to incrementally + /// clean up the caches as they fill up. + /// + /// There is no guarantee when exactly `f` will be executed. The only guarantee is that it + /// won't be executed until all currently pinned threads get unpinned. In theory, `f` might + /// never run, but the epoch-based garbage collection will make an effort to execute it + /// reasonably soon. + /// + /// If this method is called from an [`unprotected`] guard, the function will simply be + /// executed immediately. + /// + /// # Safety + /// + /// The given function must not hold reference onto the stack. It is highly recommended that + /// the passed function is **always** marked with `move` in order to prevent accidental + /// borrows. + /// + /// ``` + /// use crossbeam_epoch as epoch; + /// + /// let guard = &epoch::pin(); + /// let message = "Hello!"; + /// unsafe { + /// // ALWAYS use `move` when sending a closure into `defer_unchecked`. + /// guard.defer_unchecked(move || { + /// println!("{}", message); + /// }); + /// } + /// ``` + /// + /// Apart from that, keep in mind that another thread may execute `f`, so anything accessed by + /// the closure must be `Send`. + /// + /// We intentionally didn't require `F: Send`, because Rust's type systems usually cannot prove + /// `F: Send` for typical use cases. For example, consider the following code snippet, which + /// exemplifies the typical use case of deferring the deallocation of a shared reference: + /// + /// ```ignore + /// let shared = Owned::new(7i32).into_shared(guard); + /// guard.defer_unchecked(move || shared.into_owned()); // `Shared` is not `Send`! + /// ``` + /// + /// While `Shared` is not `Send`, it's safe for another thread to call the deferred function, + /// because it's called only after the grace period and `shared` is no longer shared with other + /// threads. But we don't expect type systems to prove this. + /// + /// # Examples + /// + /// When a heap-allocated object in a data structure becomes unreachable, it has to be + /// deallocated. However, the current thread and other threads may be still holding references + /// on the stack to that same object. Therefore it cannot be deallocated before those references + /// get dropped. This method can defer deallocation until all those threads get unpinned and + /// consequently drop all their references on the stack. + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new("foo"); + /// + /// // Now suppose that `a` is shared among multiple threads and concurrently + /// // accessed and modified... + /// + /// // Pin the current thread. + /// let guard = &epoch::pin(); + /// + /// // Steal the object currently stored in `a` and swap it with another one. + /// let p = a.swap(Owned::new("bar").into_shared(guard), SeqCst, guard); + /// + /// if !p.is_null() { + /// // The object `p` is pointing to is now unreachable. + /// // Defer its deallocation until all currently pinned threads get unpinned. + /// unsafe { + /// // ALWAYS use `move` when sending a closure into `defer_unchecked`. + /// guard.defer_unchecked(move || { + /// println!("{} is now being deallocated.", p.deref()); + /// // Now we have unique access to the object pointed to by `p` and can turn it + /// // into an `Owned`. Dropping the `Owned` will deallocate the object. + /// drop(p.into_owned()); + /// }); + /// } + /// } + /// ``` + pub unsafe fn defer_unchecked(&self, f: F) + where + F: FnOnce() -> R, + { + if let Some(local) = self.local.as_ref() { + local.defer(Deferred::new(move || drop(f())), self); + } else { + drop(f()); + } + } + + /// Stores a destructor for an object so that it can be deallocated and dropped at some point + /// after all currently pinned threads get unpinned. + /// + /// This method first stores the destructor into the thread-local (or handle-local) cache. If + /// this cache becomes full, some destructors are moved into the global cache. At the same + /// time, some destructors from both local and global caches may get executed in order to + /// incrementally clean up the caches as they fill up. + /// + /// There is no guarantee when exactly the destructor will be executed. The only guarantee is + /// that it won't be executed until all currently pinned threads get unpinned. In theory, the + /// destructor might never run, but the epoch-based garbage collection will make an effort to + /// execute it reasonably soon. + /// + /// If this method is called from an [`unprotected`] guard, the destructor will simply be + /// executed immediately. + /// + /// # Safety + /// + /// The object must not be reachable by other threads anymore, otherwise it might be still in + /// use when the destructor runs. + /// + /// Apart from that, keep in mind that another thread may execute the destructor, so the object + /// must be sendable to other threads. + /// + /// We intentionally didn't require `T: Send`, because Rust's type systems usually cannot prove + /// `T: Send` for typical use cases. For example, consider the following code snippet, which + /// exemplifies the typical use case of deferring the deallocation of a shared reference: + /// + /// ```ignore + /// let shared = Owned::new(7i32).into_shared(guard); + /// guard.defer_destroy(shared); // `Shared` is not `Send`! + /// ``` + /// + /// While `Shared` is not `Send`, it's safe for another thread to call the destructor, because + /// it's called only after the grace period and `shared` is no longer shared with other + /// threads. But we don't expect type systems to prove this. + /// + /// # Examples + /// + /// When a heap-allocated object in a data structure becomes unreachable, it has to be + /// deallocated. However, the current thread and other threads may be still holding references + /// on the stack to that same object. Therefore it cannot be deallocated before those references + /// get dropped. This method can defer deallocation until all those threads get unpinned and + /// consequently drop all their references on the stack. + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new("foo"); + /// + /// // Now suppose that `a` is shared among multiple threads and concurrently + /// // accessed and modified... + /// + /// // Pin the current thread. + /// let guard = &epoch::pin(); + /// + /// // Steal the object currently stored in `a` and swap it with another one. + /// let p = a.swap(Owned::new("bar").into_shared(guard), SeqCst, guard); + /// + /// if !p.is_null() { + /// // The object `p` is pointing to is now unreachable. + /// // Defer its deallocation until all currently pinned threads get unpinned. + /// unsafe { + /// guard.defer_destroy(p); + /// } + /// } + /// ``` + pub unsafe fn defer_destroy(&self, ptr: Shared<'_, T>) { + self.defer_unchecked(move || ptr.into_owned()); + } + + /// Clears up the thread-local cache of deferred functions by executing them or moving into the + /// global cache. + /// + /// Call this method after deferring execution of a function if you want to get it executed as + /// soon as possible. Flushing will make sure it is residing in in the global cache, so that + /// any thread has a chance of taking the function and executing it. + /// + /// If this method is called from an [`unprotected`] guard, it is a no-op (nothing happens). + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch as epoch; + /// + /// let guard = &epoch::pin(); + /// guard.defer(move || { + /// println!("This better be printed as soon as possible!"); + /// }); + /// guard.flush(); + /// ``` + pub fn flush(&self) { + if let Some(local) = unsafe { self.local.as_ref() } { + local.flush(self); + } + } + + /// Unpins and then immediately re-pins the thread. + /// + /// This method is useful when you don't want delay the advancement of the global epoch by + /// holding an old epoch. For safety, you should not maintain any guard-based reference across + /// the call (the latter is enforced by `&mut self`). The thread will only be repinned if this + /// is the only active guard for the current thread. + /// + /// If this method is called from an [`unprotected`] guard, then the call will be just no-op. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// let a = Atomic::new(777); + /// let mut guard = epoch::pin(); + /// { + /// let p = a.load(SeqCst, &guard); + /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); + /// } + /// guard.repin(); + /// { + /// let p = a.load(SeqCst, &guard); + /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); + /// } + /// ``` + pub fn repin(&mut self) { + if let Some(local) = unsafe { self.local.as_ref() } { + local.repin(); + } + } + + /// Temporarily unpins the thread, executes the given function and then re-pins the thread. + /// + /// This method is useful when you need to perform a long-running operation (e.g. sleeping) + /// and don't need to maintain any guard-based reference across the call (the latter is enforced + /// by `&mut self`). The thread will only be unpinned if this is the only active guard for the + /// current thread. + /// + /// If this method is called from an [`unprotected`] guard, then the passed function is called + /// directly without unpinning the thread. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch::{self as epoch, Atomic}; + /// use std::sync::atomic::Ordering::SeqCst; + /// use std::thread; + /// use std::time::Duration; + /// + /// let a = Atomic::new(777); + /// let mut guard = epoch::pin(); + /// { + /// let p = a.load(SeqCst, &guard); + /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); + /// } + /// guard.repin_after(|| thread::sleep(Duration::from_millis(50))); + /// { + /// let p = a.load(SeqCst, &guard); + /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); + /// } + /// ``` + pub fn repin_after(&mut self, f: F) -> R + where + F: FnOnce() -> R, + { + if let Some(local) = unsafe { self.local.as_ref() } { + // We need to acquire a handle here to ensure the Local doesn't + // disappear from under us. + local.acquire_handle(); + local.unpin(); + } + + // Ensure the Guard is re-pinned even if the function panics + defer! { + if let Some(local) = unsafe { self.local.as_ref() } { + mem::forget(local.pin()); + local.release_handle(); + } + } + + f() + } + + /// Returns the `Collector` associated with this guard. + /// + /// This method is useful when you need to ensure that all guards used with + /// a data structure come from the same collector. + /// + /// If this method is called from an [`unprotected`] guard, then `None` is returned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_epoch as epoch; + /// + /// let guard1 = epoch::pin(); + /// let guard2 = epoch::pin(); + /// assert!(guard1.collector() == guard2.collector()); + /// ``` + pub fn collector(&self) -> Option<&Collector> { + unsafe { self.local.as_ref().map(|local| local.collector()) } + } +} + +impl Drop for Guard { + #[inline] + fn drop(&mut self) { + if let Some(local) = unsafe { self.local.as_ref() } { + local.unpin(); + } + } +} + +impl fmt::Debug for Guard { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Guard { .. }") + } +} + +/// Returns a reference to a dummy guard that allows unprotected access to [`Atomic`]s. +/// +/// This guard should be used in special occasions only. Note that it doesn't actually keep any +/// thread pinned - it's just a fake guard that allows loading from [`Atomic`]s unsafely. +/// +/// Note that calling [`defer`] with a dummy guard will not defer the function - it will just +/// execute the function immediately. +/// +/// If necessary, it's possible to create more dummy guards by cloning: `unprotected().clone()`. +/// +/// # Safety +/// +/// Loading and dereferencing data from an [`Atomic`] using this guard is safe only if the +/// [`Atomic`] is not being concurrently modified by other threads. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_epoch::{self as epoch, Atomic}; +/// use std::sync::atomic::Ordering::Relaxed; +/// +/// let a = Atomic::new(7); +/// +/// unsafe { +/// // Load `a` without pinning the current thread. +/// a.load(Relaxed, epoch::unprotected()); +/// +/// // It's possible to create more dummy guards by calling `clone()`. +/// let dummy = &epoch::unprotected().clone(); +/// +/// dummy.defer(move || { +/// println!("This gets executed immediately."); +/// }); +/// +/// // Dropping `dummy` doesn't affect the current thread - it's just a noop. +/// } +/// ``` +/// +/// The most common use of this function is when constructing or destructing a data structure. +/// +/// For example, we can use a dummy guard in the destructor of a Treiber stack because at that +/// point no other thread could concurrently modify the [`Atomic`]s we are accessing. +/// +/// If we were to actually pin the current thread during destruction, that would just unnecessarily +/// delay garbage collection and incur some performance cost, so in cases like these `unprotected` +/// is very helpful. +/// +/// ``` +/// use crossbeam_epoch::{self as epoch, Atomic}; +/// use std::mem::ManuallyDrop; +/// use std::sync::atomic::Ordering::Relaxed; +/// +/// struct Stack { +/// head: Atomic>, +/// } +/// +/// struct Node { +/// data: ManuallyDrop, +/// next: Atomic>, +/// } +/// +/// impl Drop for Stack { +/// fn drop(&mut self) { +/// unsafe { +/// // Unprotected load. +/// let mut node = self.head.load(Relaxed, epoch::unprotected()); +/// +/// while let Some(n) = node.as_ref() { +/// // Unprotected load. +/// let next = n.next.load(Relaxed, epoch::unprotected()); +/// +/// // Take ownership of the node, then drop its data and deallocate it. +/// let mut o = node.into_owned(); +/// ManuallyDrop::drop(&mut o.data); +/// drop(o); +/// +/// node = next; +/// } +/// } +/// } +/// } +/// ``` +/// +/// [`Atomic`]: super::Atomic +/// [`defer`]: Guard::defer +#[inline] +pub unsafe fn unprotected() -> &'static Guard { + // An unprotected guard is just a `Guard` with its field `local` set to null. + // We make a newtype over `Guard` because `Guard` isn't `Sync`, so can't be directly stored in + // a `static` + struct GuardWrapper(Guard); + unsafe impl Sync for GuardWrapper {} + static UNPROTECTED: GuardWrapper = GuardWrapper(Guard { + local: core::ptr::null(), + }); + &UNPROTECTED.0 +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/internal.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/internal.rs new file mode 100644 index 0000000..bf2dfb8 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/internal.rs @@ -0,0 +1,663 @@ +//! The global data and participant for garbage collection. +//! +//! # Registration +//! +//! In order to track all participants in one place, we need some form of participant +//! registration. When a participant is created, it is registered to a global lock-free +//! singly-linked list of registries; and when a participant is leaving, it is unregistered from the +//! list. +//! +//! # Pinning +//! +//! Every participant contains an integer that tells whether the participant is pinned and if so, +//! what was the global epoch at the time it was pinned. Participants also hold a pin counter that +//! aids in periodic global epoch advancement. +//! +//! When a participant is pinned, a `Guard` is returned as a witness that the participant is pinned. +//! Guards are necessary for performing atomic operations, and for freeing/dropping locations. +//! +//! # Thread-local bag +//! +//! Objects that get unlinked from concurrent data structures must be stashed away until the global +//! epoch sufficiently advances so that they become safe for destruction. Pointers to such objects +//! are pushed into a thread-local bag, and when it becomes full, the bag is marked with the current +//! global epoch and pushed into the global queue of bags. We store objects in thread-local storages +//! for amortizing the synchronization cost of pushing the garbages to a global queue. +//! +//! # Global queue +//! +//! Whenever a bag is pushed into a queue, the objects in some bags in the queue are collected and +//! destroyed along the way. This design reduces contention on data structures. The global queue +//! cannot be explicitly accessed: the only way to interact with it is by calling functions +//! `defer()` that adds an object to the thread-local bag, or `collect()` that manually triggers +//! garbage collection. +//! +//! Ideally each instance of concurrent data structure may have its own queue that gets fully +//! destroyed as soon as the data structure gets dropped. + +use core::cell::{Cell, UnsafeCell}; +use core::mem::{self, ManuallyDrop}; +use core::num::Wrapping; +use core::sync::atomic; +use core::sync::atomic::Ordering; +use core::{fmt, ptr}; + +use crossbeam_utils::CachePadded; +use memoffset::offset_of; + +use crate::atomic::{Owned, Shared}; +use crate::collector::{Collector, LocalHandle}; +use crate::deferred::Deferred; +use crate::epoch::{AtomicEpoch, Epoch}; +use crate::guard::{unprotected, Guard}; +use crate::sync::list::{Entry, IsElement, IterError, List}; +use crate::sync::queue::Queue; + +/// Maximum number of objects a bag can contain. +#[cfg(not(feature = "sanitize"))] +const MAX_OBJECTS: usize = 62; +#[cfg(feature = "sanitize")] +const MAX_OBJECTS: usize = 4; + +/// A bag of deferred functions. +pub struct Bag { + /// Stashed objects. + deferreds: [Deferred; MAX_OBJECTS], + len: usize, +} + +/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions. +unsafe impl Send for Bag {} + +impl Bag { + /// Returns a new, empty bag. + pub fn new() -> Self { + Self::default() + } + + /// Returns `true` if the bag is empty. + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Attempts to insert a deferred function into the bag. + /// + /// Returns `Ok(())` if successful, and `Err(deferred)` for the given `deferred` if the bag is + /// full. + /// + /// # Safety + /// + /// It should be safe for another thread to execute the given function. + pub unsafe fn try_push(&mut self, deferred: Deferred) -> Result<(), Deferred> { + if self.len < MAX_OBJECTS { + self.deferreds[self.len] = deferred; + self.len += 1; + Ok(()) + } else { + Err(deferred) + } + } + + /// Seals the bag with the given epoch. + fn seal(self, epoch: Epoch) -> SealedBag { + SealedBag { epoch, bag: self } + } +} + +impl Default for Bag { + #[rustfmt::skip] + fn default() -> Self { + // TODO: [no_op; MAX_OBJECTS] syntax blocked by https://github.com/rust-lang/rust/issues/49147 + #[cfg(not(feature = "sanitize"))] + return Bag { + len: 0, + deferreds: [ + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + ], + }; + #[cfg(feature = "sanitize")] + return Bag { + len: 0, + deferreds: [ + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + Deferred::new(no_op_func), + ], + }; + } +} + +impl Drop for Bag { + fn drop(&mut self) { + // Call all deferred functions. + for deferred in &mut self.deferreds[..self.len] { + let no_op = Deferred::new(no_op_func); + let owned_deferred = mem::replace(deferred, no_op); + owned_deferred.call(); + } + } +} + +// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long +impl fmt::Debug for Bag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Bag") + .field("deferreds", &&self.deferreds[..self.len]) + .finish() + } +} + +fn no_op_func() {} + +/// A pair of an epoch and a bag. +#[derive(Default, Debug)] +struct SealedBag { + epoch: Epoch, + bag: Bag, +} + +/// It is safe to share `SealedBag` because `is_expired` only inspects the epoch. +unsafe impl Sync for SealedBag {} + +impl SealedBag { + /// Checks if it is safe to drop the bag w.r.t. the given global epoch. + fn is_expired(&self, global_epoch: Epoch) -> bool { + // A pinned participant can witness at most one epoch advancement. Therefore, any bag that + // is within one epoch of the current one cannot be destroyed yet. + global_epoch.wrapping_sub(self.epoch) >= 2 + } +} + +/// The global data for a garbage collector. +pub struct Global { + /// The intrusive linked list of `Local`s. + locals: List, + + /// The global queue of bags of deferred functions. + queue: Queue, + + /// The global epoch. + pub(crate) epoch: CachePadded, +} + +impl Global { + /// Number of bags to destroy. + const COLLECT_STEPS: usize = 8; + + /// Creates a new global data for garbage collection. + #[inline] + pub fn new() -> Self { + Self { + locals: List::new(), + queue: Queue::new(), + epoch: CachePadded::new(AtomicEpoch::new(Epoch::starting())), + } + } + + /// Pushes the bag into the global queue and replaces the bag with a new empty bag. + pub fn push_bag(&self, bag: &mut Bag, guard: &Guard) { + let bag = mem::replace(bag, Bag::new()); + + atomic::fence(Ordering::SeqCst); + + let epoch = self.epoch.load(Ordering::Relaxed); + self.queue.push(bag.seal(epoch), guard); + } + + /// Collects several bags from the global queue and executes deferred functions in them. + /// + /// Note: This may itself produce garbage and in turn allocate new bags. + /// + /// `pin()` rarely calls `collect()`, so we want the compiler to place that call on a cold + /// path. In other words, we want the compiler to optimize branching for the case when + /// `collect()` is not called. + #[cold] + pub fn collect(&self, guard: &Guard) { + let global_epoch = self.try_advance(guard); + + let steps = if cfg!(feature = "sanitize") { + usize::max_value() + } else { + Self::COLLECT_STEPS + }; + + for _ in 0..steps { + match self.queue.try_pop_if( + &|sealed_bag: &SealedBag| sealed_bag.is_expired(global_epoch), + guard, + ) { + None => break, + Some(sealed_bag) => drop(sealed_bag), + } + } + } + + /// Attempts to advance the global epoch. + /// + /// The global epoch can advance only if all currently pinned participants have been pinned in + /// the current epoch. + /// + /// Returns the current global epoch. + /// + /// `try_advance()` is annotated `#[cold]` because it is rarely called. + #[cold] + pub fn try_advance(&self, guard: &Guard) -> Epoch { + let global_epoch = self.epoch.load(Ordering::Relaxed); + atomic::fence(Ordering::SeqCst); + + // TODO(stjepang): `Local`s are stored in a linked list because linked lists are fairly + // easy to implement in a lock-free manner. However, traversal can be slow due to cache + // misses and data dependencies. We should experiment with other data structures as well. + for local in self.locals.iter(&guard) { + match local { + Err(IterError::Stalled) => { + // A concurrent thread stalled this iteration. That thread might also try to + // advance the epoch, in which case we leave the job to it. Otherwise, the + // epoch will not be advanced. + return global_epoch; + } + Ok(local) => { + let local_epoch = local.epoch.load(Ordering::Relaxed); + + // If the participant was pinned in a different epoch, we cannot advance the + // global epoch just yet. + if local_epoch.is_pinned() && local_epoch.unpinned() != global_epoch { + return global_epoch; + } + } + } + } + atomic::fence(Ordering::Acquire); + + // All pinned participants were pinned in the current global epoch. + // Now let's advance the global epoch... + // + // Note that if another thread already advanced it before us, this store will simply + // overwrite the global epoch with the same value. This is true because `try_advance` was + // called from a thread that was pinned in `global_epoch`, and the global epoch cannot be + // advanced two steps ahead of it. + let new_epoch = global_epoch.successor(); + self.epoch.store(new_epoch, Ordering::Release); + new_epoch + } +} + +/// Participant for garbage collection. +pub struct Local { + /// A node in the intrusive linked list of `Local`s. + entry: Entry, + + /// The local epoch. + epoch: AtomicEpoch, + + /// A reference to the global data. + /// + /// When all guards and handles get dropped, this reference is destroyed. + collector: UnsafeCell>, + + /// The local bag of deferred functions. + pub(crate) bag: UnsafeCell, + + /// The number of guards keeping this participant pinned. + guard_count: Cell, + + /// The number of active handles. + handle_count: Cell, + + /// Total number of pinnings performed. + /// + /// This is just an auxiliary counter that sometimes kicks off collection. + pin_count: Cell>, +} + +// Make sure `Local` is less than or equal to 2048 bytes. +// https://github.com/crossbeam-rs/crossbeam/issues/551 +#[test] +fn local_size() { + assert!(core::mem::size_of::() <= 2048, "An allocation of `Local` should be <= 2048 bytes."); +} + +impl Local { + /// Number of pinnings after which a participant will execute some deferred functions from the + /// global queue. + const PINNINGS_BETWEEN_COLLECT: usize = 128; + + /// Registers a new `Local` in the provided `Global`. + pub fn register(collector: &Collector) -> LocalHandle { + unsafe { + // Since we dereference no pointers in this block, it is safe to use `unprotected`. + + let local = Owned::new(Local { + entry: Entry::default(), + epoch: AtomicEpoch::new(Epoch::starting()), + collector: UnsafeCell::new(ManuallyDrop::new(collector.clone())), + bag: UnsafeCell::new(Bag::new()), + guard_count: Cell::new(0), + handle_count: Cell::new(1), + pin_count: Cell::new(Wrapping(0)), + }) + .into_shared(unprotected()); + collector.global.locals.insert(local, unprotected()); + LocalHandle { + local: local.as_raw(), + } + } + } + + /// Returns a reference to the `Global` in which this `Local` resides. + #[inline] + pub fn global(&self) -> &Global { + &self.collector().global + } + + /// Returns a reference to the `Collector` in which this `Local` resides. + #[inline] + pub fn collector(&self) -> &Collector { + unsafe { &**self.collector.get() } + } + + /// Returns `true` if the current participant is pinned. + #[inline] + pub fn is_pinned(&self) -> bool { + self.guard_count.get() > 0 + } + + /// Adds `deferred` to the thread-local bag. + /// + /// # Safety + /// + /// It should be safe for another thread to execute the given function. + pub unsafe fn defer(&self, mut deferred: Deferred, guard: &Guard) { + let bag = &mut *self.bag.get(); + + while let Err(d) = bag.try_push(deferred) { + self.global().push_bag(bag, guard); + deferred = d; + } + } + + pub fn flush(&self, guard: &Guard) { + let bag = unsafe { &mut *self.bag.get() }; + + if !bag.is_empty() { + self.global().push_bag(bag, guard); + } + + self.global().collect(guard); + } + + /// Pins the `Local`. + #[inline] + pub fn pin(&self) -> Guard { + let guard = Guard { local: self }; + + let guard_count = self.guard_count.get(); + self.guard_count.set(guard_count.checked_add(1).unwrap()); + + if guard_count == 0 { + let global_epoch = self.global().epoch.load(Ordering::Relaxed); + let new_epoch = global_epoch.pinned(); + + // Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence. + // The fence makes sure that any future loads from `Atomic`s will not happen before + // this store. + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // HACK(stjepang): On x86 architectures there are two different ways of executing + // a `SeqCst` fence. + // + // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction. + // 2. `_.compare_and_swap(_, _, SeqCst)`, which compiles into a `lock cmpxchg` + // instruction. + // + // Both instructions have the effect of a full barrier, but benchmarks have shown + // that the second one makes pinning faster in this particular case. It is not + // clear that this is permitted by the C++ memory model (SC fences work very + // differently from SC accesses), but experimental evidence suggests that this + // works fine. Using inline assembly would be a viable (and correct) alternative, + // but alas, that is not possible on stable Rust. + let current = Epoch::starting(); + let previous = self + .epoch + .compare_and_swap(current, new_epoch, Ordering::SeqCst); + debug_assert_eq!(current, previous, "participant was expected to be unpinned"); + // We add a compiler fence to make it less likely for LLVM to do something wrong + // here. Formally, this is not enough to get rid of data races; practically, + // it should go a long way. + atomic::compiler_fence(Ordering::SeqCst); + } else { + self.epoch.store(new_epoch, Ordering::Relaxed); + atomic::fence(Ordering::SeqCst); + } + + // Increment the pin counter. + let count = self.pin_count.get(); + self.pin_count.set(count + Wrapping(1)); + + // After every `PINNINGS_BETWEEN_COLLECT` try advancing the epoch and collecting + // some garbage. + if count.0 % Self::PINNINGS_BETWEEN_COLLECT == 0 { + self.global().collect(&guard); + } + } + + guard + } + + /// Unpins the `Local`. + #[inline] + pub fn unpin(&self) { + let guard_count = self.guard_count.get(); + self.guard_count.set(guard_count - 1); + + if guard_count == 1 { + self.epoch.store(Epoch::starting(), Ordering::Release); + + if self.handle_count.get() == 0 { + self.finalize(); + } + } + } + + /// Unpins and then pins the `Local`. + #[inline] + pub fn repin(&self) { + let guard_count = self.guard_count.get(); + + // Update the local epoch only if there's only one guard. + if guard_count == 1 { + let epoch = self.epoch.load(Ordering::Relaxed); + let global_epoch = self.global().epoch.load(Ordering::Relaxed).pinned(); + + // Update the local epoch only if the global epoch is greater than the local epoch. + if epoch != global_epoch { + // We store the new epoch with `Release` because we need to ensure any memory + // accesses from the previous epoch do not leak into the new one. + self.epoch.store(global_epoch, Ordering::Release); + + // However, we don't need a following `SeqCst` fence, because it is safe for memory + // accesses from the new epoch to be executed before updating the local epoch. At + // worse, other threads will see the new epoch late and delay GC slightly. + } + } + } + + /// Increments the handle count. + #[inline] + pub fn acquire_handle(&self) { + let handle_count = self.handle_count.get(); + debug_assert!(handle_count >= 1); + self.handle_count.set(handle_count + 1); + } + + /// Decrements the handle count. + #[inline] + pub fn release_handle(&self) { + let guard_count = self.guard_count.get(); + let handle_count = self.handle_count.get(); + debug_assert!(handle_count >= 1); + self.handle_count.set(handle_count - 1); + + if guard_count == 0 && handle_count == 1 { + self.finalize(); + } + } + + /// Removes the `Local` from the global linked list. + #[cold] + fn finalize(&self) { + debug_assert_eq!(self.guard_count.get(), 0); + debug_assert_eq!(self.handle_count.get(), 0); + + // Temporarily increment handle count. This is required so that the following call to `pin` + // doesn't call `finalize` again. + self.handle_count.set(1); + unsafe { + // Pin and move the local bag into the global queue. It's important that `push_bag` + // doesn't defer destruction on any new garbage. + let guard = &self.pin(); + self.global().push_bag(&mut *self.bag.get(), guard); + } + // Revert the handle count back to zero. + self.handle_count.set(0); + + unsafe { + // Take the reference to the `Global` out of this `Local`. Since we're not protected + // by a guard at this time, it's crucial that the reference is read before marking the + // `Local` as deleted. + let collector: Collector = ptr::read(&*(*self.collector.get())); + + // Mark this node in the linked list as deleted. + self.entry.delete(unprotected()); + + // Finally, drop the reference to the global. Note that this might be the last reference + // to the `Global`. If so, the global data will be destroyed and all deferred functions + // in its queue will be executed. + drop(collector); + } + } +} + +impl IsElement for Local { + fn entry_of(local: &Local) -> &Entry { + let entry_ptr = (local as *const Local as usize + offset_of!(Local, entry)) as *const Entry; + unsafe { &*entry_ptr } + } + + unsafe fn element_of(entry: &Entry) -> &Local { + // offset_of! macro uses unsafe, but it's unnecessary in this context. + #[allow(unused_unsafe)] + let local_ptr = (entry as *const Entry as usize - offset_of!(Local, entry)) as *const Local; + &*local_ptr + } + + unsafe fn finalize(entry: &Entry, guard: &Guard) { + guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _)); + } +} + +#[cfg(test)] +mod tests { + use std::sync::atomic::{AtomicUsize, Ordering}; + + use super::*; + + #[test] + fn check_defer() { + static FLAG: AtomicUsize = AtomicUsize::new(0); + fn set() { + FLAG.store(42, Ordering::Relaxed); + } + + let d = Deferred::new(set); + assert_eq!(FLAG.load(Ordering::Relaxed), 0); + d.call(); + assert_eq!(FLAG.load(Ordering::Relaxed), 42); + } + + #[test] + fn check_bag() { + static FLAG: AtomicUsize = AtomicUsize::new(0); + fn incr() { + FLAG.fetch_add(1, Ordering::Relaxed); + } + + let mut bag = Bag::new(); + assert!(bag.is_empty()); + + for _ in 0..MAX_OBJECTS { + assert!(unsafe { bag.try_push(Deferred::new(incr)).is_ok() }); + assert!(!bag.is_empty()); + assert_eq!(FLAG.load(Ordering::Relaxed), 0); + } + + let result = unsafe { bag.try_push(Deferred::new(incr)) }; + assert!(result.is_err()); + assert!(!bag.is_empty()); + assert_eq!(FLAG.load(Ordering::Relaxed), 0); + + drop(bag); + assert_eq!(FLAG.load(Ordering::Relaxed), MAX_OBJECTS); + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/lib.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/lib.rs new file mode 100644 index 0000000..f64d16c --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/lib.rs @@ -0,0 +1,91 @@ +//! Epoch-based memory reclamation. +//! +//! An interesting problem concurrent collections deal with comes from the remove operation. +//! Suppose that a thread removes an element from a lock-free map, while another thread is reading +//! that same element at the same time. The first thread must wait until the second thread stops +//! reading the element. Only then it is safe to destruct it. +//! +//! Programming languages that come with garbage collectors solve this problem trivially. The +//! garbage collector will destruct the removed element when no thread can hold a reference to it +//! anymore. +//! +//! This crate implements a basic memory reclamation mechanism, which is based on epochs. When an +//! element gets removed from a concurrent collection, it is inserted into a pile of garbage and +//! marked with the current epoch. Every time a thread accesses a collection, it checks the current +//! epoch, attempts to increment it, and destructs some garbage that became so old that no thread +//! can be referencing it anymore. +//! +//! That is the general mechanism behind epoch-based memory reclamation, but the details are a bit +//! more complicated. Anyhow, memory reclamation is designed to be fully automatic and something +//! users of concurrent collections don't have to worry much about. +//! +//! # Pointers +//! +//! Concurrent collections are built using atomic pointers. This module provides [`Atomic`], which +//! is just a shared atomic pointer to a heap-allocated object. Loading an [`Atomic`] yields a +//! [`Shared`], which is an epoch-protected pointer through which the loaded object can be safely +//! read. +//! +//! # Pinning +//! +//! Before an [`Atomic`] can be loaded, a participant must be [`pin`]ned. By pinning a participant +//! we declare that any object that gets removed from now on must not be destructed just +//! yet. Garbage collection of newly removed objects is suspended until the participant gets +//! unpinned. +//! +//! # Garbage +//! +//! Objects that get removed from concurrent collections must be stashed away until all currently +//! pinned participants get unpinned. Such objects can be stored into a thread-local or global +//! storage, where they are kept until the right time for their destruction comes. +//! +//! There is a global shared instance of garbage queue. You can [`defer`](Guard::defer) the execution of an +//! arbitrary function until the global epoch is advanced enough. Most notably, concurrent data +//! structures may defer the deallocation of an object. +//! +//! # APIs +//! +//! For majority of use cases, just use the default garbage collector by invoking [`pin`]. If you +//! want to create your own garbage collector, use the [`Collector`] API. + +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms), + allow(dead_code, unused_assignments, unused_variables) + ) +))] +#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] +#![cfg_attr(feature = "nightly", feature(const_fn))] +// matches! requires Rust 1.42 +#![allow(clippy::match_like_matches_macro)] + +use cfg_if::cfg_if; + +#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] +cfg_if! { + if #[cfg(feature = "alloc")] { + extern crate alloc; + + mod atomic; + mod collector; + mod deferred; + mod epoch; + mod guard; + mod internal; + mod sync; + + pub use self::atomic::{Pointable, Atomic, CompareAndSetError, CompareAndSetOrdering, Owned, Pointer, Shared}; + pub use self::collector::{Collector, LocalHandle}; + pub use self::guard::{unprotected, Guard}; + } +} + +cfg_if! { + if #[cfg(feature = "std")] { + mod default; + pub use self::default::{default_collector, is_pinned, pin}; + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/list.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/list.rs new file mode 100644 index 0000000..656e2a8 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/list.rs @@ -0,0 +1,487 @@ +//! Lock-free intrusive linked list. +//! +//! Ideas from Michael. High Performance Dynamic Lock-Free Hash Tables and List-Based Sets. SPAA +//! 2002. + +use core::marker::PhantomData; +use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; + +use crate::{unprotected, Atomic, Guard, Shared}; + +/// An entry in a linked list. +/// +/// An Entry is accessed from multiple threads, so it would be beneficial to put it in a different +/// cache-line than thread-local data in terms of performance. +#[derive(Debug)] +pub struct Entry { + /// The next entry in the linked list. + /// If the tag is 1, this entry is marked as deleted. + next: Atomic, +} + +/// Implementing this trait asserts that the type `T` can be used as an element in the intrusive +/// linked list defined in this module. `T` has to contain (or otherwise be linked to) an instance +/// of `Entry`. +/// +/// # Example +/// +/// ```ignore +/// struct A { +/// entry: Entry, +/// data: usize, +/// } +/// +/// impl IsElement for A { +/// fn entry_of(a: &A) -> &Entry { +/// let entry_ptr = ((a as usize) + offset_of!(A, entry)) as *const Entry; +/// unsafe { &*entry_ptr } +/// } +/// +/// unsafe fn element_of(entry: &Entry) -> &T { +/// let elem_ptr = ((entry as usize) - offset_of!(A, entry)) as *const T; +/// &*elem_ptr +/// } +/// +/// unsafe fn finalize(entry: &Entry, guard: &Guard) { +/// guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _)); +/// } +/// } +/// ``` +/// +/// This trait is implemented on a type separate from `T` (although it can be just `T`), because +/// one type might be placeable into multiple lists, in which case it would require multiple +/// implementations of `IsElement`. In such cases, each struct implementing `IsElement` +/// represents a distinct `Entry` in `T`. +/// +/// For example, we can insert the following struct into two lists using `entry1` for one +/// and `entry2` for the other: +/// +/// ```ignore +/// struct B { +/// entry1: Entry, +/// entry2: Entry, +/// data: usize, +/// } +/// ``` +/// +pub trait IsElement { + /// Returns a reference to this element's `Entry`. + fn entry_of(_: &T) -> &Entry; + + /// Given a reference to an element's entry, returns that element. + /// + /// ```ignore + /// let elem = ListElement::new(); + /// assert_eq!(elem.entry_of(), + /// unsafe { ListElement::element_of(elem.entry_of()) } ); + /// ``` + /// + /// # Safety + /// + /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance + /// of the element type (`T`). + unsafe fn element_of(_: &Entry) -> &T; + + /// The function that is called when an entry is unlinked from list. + /// + /// # Safety + /// + /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance + /// of the element type (`T`). + unsafe fn finalize(_: &Entry, _: &Guard); +} + +/// A lock-free, intrusive linked list of type `T`. +#[derive(Debug)] +pub struct List = T> { + /// The head of the linked list. + head: Atomic, + + /// The phantom data for using `T` and `C`. + _marker: PhantomData<(T, C)>, +} + +/// An iterator used for retrieving values from the list. +pub struct Iter<'g, T, C: IsElement> { + /// The guard that protects the iteration. + guard: &'g Guard, + + /// Pointer from the predecessor to the current entry. + pred: &'g Atomic, + + /// The current entry. + curr: Shared<'g, Entry>, + + /// The list head, needed for restarting iteration. + head: &'g Atomic, + + /// Logically, we store a borrow of an instance of `T` and + /// use the type information from `C`. + _marker: PhantomData<(&'g T, C)>, +} + +/// An error that occurs during iteration over the list. +#[derive(PartialEq, Debug)] +pub enum IterError { + /// A concurrent thread modified the state of the list at the same place that this iterator + /// was inspecting. Subsequent iteration will restart from the beginning of the list. + Stalled, +} + +impl Default for Entry { + /// Returns the empty entry. + fn default() -> Self { + Self { + next: Atomic::null(), + } + } +} + +impl Entry { + /// Marks this entry as deleted, deferring the actual deallocation to a later iteration. + /// + /// # Safety + /// + /// The entry should be a member of a linked list, and it should not have been deleted. + /// It should be safe to call `C::finalize` on the entry after the `guard` is dropped, where `C` + /// is the associated helper for the linked list. + pub unsafe fn delete(&self, guard: &Guard) { + self.next.fetch_or(1, Release, guard); + } +} + +impl> List { + /// Returns a new, empty linked list. + pub fn new() -> Self { + Self { + head: Atomic::null(), + _marker: PhantomData, + } + } + + /// Inserts `entry` into the head of the list. + /// + /// # Safety + /// + /// You should guarantee that: + /// + /// - `container` is not null + /// - `container` is immovable, e.g. inside an `Owned` + /// - the same `Entry` is not inserted more than once + /// - the inserted object will be removed before the list is dropped + pub unsafe fn insert<'g>(&'g self, container: Shared<'g, T>, guard: &'g Guard) { + // Insert right after head, i.e. at the beginning of the list. + let to = &self.head; + // Get the intrusively stored Entry of the new element to insert. + let entry: &Entry = C::entry_of(container.deref()); + // Make a Shared ptr to that Entry. + let entry_ptr = Shared::from(entry as *const _); + // Read the current successor of where we want to insert. + let mut next = to.load(Relaxed, guard); + + loop { + // Set the Entry of the to-be-inserted element to point to the previous successor of + // `to`. + entry.next.store(next, Relaxed); + match to.compare_and_set_weak(next, entry_ptr, Release, guard) { + Ok(_) => break, + // We lost the race or weak CAS failed spuriously. Update the successor and try + // again. + Err(err) => next = err.current, + } + } + } + + /// Returns an iterator over all objects. + /// + /// # Caveat + /// + /// Every object that is inserted at the moment this function is called and persists at least + /// until the end of iteration will be returned. Since this iterator traverses a lock-free + /// linked list that may be concurrently modified, some additional caveats apply: + /// + /// 1. If a new object is inserted during iteration, it may or may not be returned. + /// 2. If an object is deleted during iteration, it may or may not be returned. + /// 3. The iteration may be aborted when it lost in a race condition. In this case, the winning + /// thread will continue to iterate over the same list. + pub fn iter<'g>(&'g self, guard: &'g Guard) -> Iter<'g, T, C> { + Iter { + guard, + pred: &self.head, + curr: self.head.load(Acquire, guard), + head: &self.head, + _marker: PhantomData, + } + } +} + +impl> Drop for List { + fn drop(&mut self) { + unsafe { + let guard = unprotected(); + let mut curr = self.head.load(Relaxed, guard); + while let Some(c) = curr.as_ref() { + let succ = c.next.load(Relaxed, guard); + // Verify that all elements have been removed from the list. + assert_eq!(succ.tag(), 1); + + C::finalize(curr.deref(), guard); + curr = succ; + } + } + } +} + +impl<'g, T: 'g, C: IsElement> Iterator for Iter<'g, T, C> { + type Item = Result<&'g T, IterError>; + + fn next(&mut self) -> Option { + while let Some(c) = unsafe { self.curr.as_ref() } { + let succ = c.next.load(Acquire, self.guard); + + if succ.tag() == 1 { + // This entry was removed. Try unlinking it from the list. + let succ = succ.with_tag(0); + + // The tag should always be zero, because removing a node after a logically deleted + // node leaves the list in an invalid state. + debug_assert!(self.curr.tag() == 0); + + // Try to unlink `curr` from the list, and get the new value of `self.pred`. + let succ = match self + .pred + .compare_and_set(self.curr, succ, Acquire, self.guard) + { + Ok(_) => { + // We succeeded in unlinking `curr`, so we have to schedule + // deallocation. Deferred drop is okay, because `list.delete()` can only be + // called if `T: 'static`. + unsafe { + C::finalize(self.curr.deref(), self.guard); + } + + // `succ` is the new value of `self.pred`. + succ + } + Err(e) => { + // `e.current` is the current value of `self.pred`. + e.current + } + }; + + // If the predecessor node is already marked as deleted, we need to restart from + // `head`. + if succ.tag() != 0 { + self.pred = self.head; + self.curr = self.head.load(Acquire, self.guard); + + return Some(Err(IterError::Stalled)); + } + + // Move over the removed by only advancing `curr`, not `pred`. + self.curr = succ; + continue; + } + + // Move one step forward. + self.pred = &c.next; + self.curr = succ; + + return Some(Ok(unsafe { C::element_of(c) })); + } + + // We reached the end of the list. + None + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Collector, Owned}; + use crossbeam_utils::thread; + use std::sync::Barrier; + + impl IsElement for Entry { + fn entry_of(entry: &Entry) -> &Entry { + entry + } + + unsafe fn element_of(entry: &Entry) -> &Entry { + entry + } + + unsafe fn finalize(entry: &Entry, guard: &Guard) { + guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _)); + } + } + + /// Checks whether the list retains inserted elements + /// and returns them in the correct order. + #[test] + fn insert() { + let collector = Collector::new(); + let handle = collector.register(); + let guard = handle.pin(); + + let l: List = List::new(); + + let e1 = Owned::new(Entry::default()).into_shared(&guard); + let e2 = Owned::new(Entry::default()).into_shared(&guard); + let e3 = Owned::new(Entry::default()).into_shared(&guard); + + unsafe { + l.insert(e1, &guard); + l.insert(e2, &guard); + l.insert(e3, &guard); + } + + let mut iter = l.iter(&guard); + let maybe_e3 = iter.next(); + assert!(maybe_e3.is_some()); + assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw()); + let maybe_e2 = iter.next(); + assert!(maybe_e2.is_some()); + assert!(maybe_e2.unwrap().unwrap() as *const Entry == e2.as_raw()); + let maybe_e1 = iter.next(); + assert!(maybe_e1.is_some()); + assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw()); + assert!(iter.next().is_none()); + + unsafe { + e1.as_ref().unwrap().delete(&guard); + e2.as_ref().unwrap().delete(&guard); + e3.as_ref().unwrap().delete(&guard); + } + } + + /// Checks whether elements can be removed from the list and whether + /// the correct elements are removed. + #[test] + fn delete() { + let collector = Collector::new(); + let handle = collector.register(); + let guard = handle.pin(); + + let l: List = List::new(); + + let e1 = Owned::new(Entry::default()).into_shared(&guard); + let e2 = Owned::new(Entry::default()).into_shared(&guard); + let e3 = Owned::new(Entry::default()).into_shared(&guard); + unsafe { + l.insert(e1, &guard); + l.insert(e2, &guard); + l.insert(e3, &guard); + e2.as_ref().unwrap().delete(&guard); + } + + let mut iter = l.iter(&guard); + let maybe_e3 = iter.next(); + assert!(maybe_e3.is_some()); + assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw()); + let maybe_e1 = iter.next(); + assert!(maybe_e1.is_some()); + assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw()); + assert!(iter.next().is_none()); + + unsafe { + e1.as_ref().unwrap().delete(&guard); + e3.as_ref().unwrap().delete(&guard); + } + + let mut iter = l.iter(&guard); + assert!(iter.next().is_none()); + } + + const THREADS: usize = 8; + const ITERS: usize = 512; + + /// Contends the list on insert and delete operations to make sure they can run concurrently. + #[test] + fn insert_delete_multi() { + let collector = Collector::new(); + + let l: List = List::new(); + let b = Barrier::new(THREADS); + + thread::scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + b.wait(); + + let handle = collector.register(); + let guard: Guard = handle.pin(); + let mut v = Vec::with_capacity(ITERS); + + for _ in 0..ITERS { + let e = Owned::new(Entry::default()).into_shared(&guard); + v.push(e); + unsafe { + l.insert(e, &guard); + } + } + + for e in v { + unsafe { + e.as_ref().unwrap().delete(&guard); + } + } + }); + } + }) + .unwrap(); + + let handle = collector.register(); + let guard = handle.pin(); + + let mut iter = l.iter(&guard); + assert!(iter.next().is_none()); + } + + /// Contends the list on iteration to make sure that it can be iterated over concurrently. + #[test] + fn iter_multi() { + let collector = Collector::new(); + + let l: List = List::new(); + let b = Barrier::new(THREADS); + + thread::scope(|s| { + for _ in 0..THREADS { + s.spawn(|_| { + b.wait(); + + let handle = collector.register(); + let guard: Guard = handle.pin(); + let mut v = Vec::with_capacity(ITERS); + + for _ in 0..ITERS { + let e = Owned::new(Entry::default()).into_shared(&guard); + v.push(e); + unsafe { + l.insert(e, &guard); + } + } + + let mut iter = l.iter(&guard); + for _ in 0..ITERS { + assert!(iter.next().is_some()); + } + + for e in v { + unsafe { + e.as_ref().unwrap().delete(&guard); + } + } + }); + } + }) + .unwrap(); + + let handle = collector.register(); + let guard = handle.pin(); + + let mut iter = l.iter(&guard); + assert!(iter.next().is_none()); + } +} diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/mod.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/mod.rs new file mode 100644 index 0000000..f8eb259 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/mod.rs @@ -0,0 +1,4 @@ +//! Synchronization primitives. + +pub mod list; +pub mod queue; diff --git a/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/queue.rs b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/queue.rs new file mode 100644 index 0000000..71ea1bc --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-epoch-0.9.1/src/sync/queue.rs @@ -0,0 +1,458 @@ +//! Michael-Scott lock-free queue. +//! +//! Usable with any number of producers and consumers. +//! +//! Michael and Scott. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue +//! Algorithms. PODC 1996. +//! +//! Simon Doherty, Lindsay Groves, Victor Luchangco, and Mark Moir. 2004b. Formal Verification of a +//! Practical Lock-Free Queue Algorithm. + +use core::mem::MaybeUninit; +use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; + +use crossbeam_utils::CachePadded; + +use crate::{unprotected, Atomic, Guard, Owned, Shared}; + +// The representation here is a singly-linked list, with a sentinel node at the front. In general +// the `tail` pointer may lag behind the actual tail. Non-sentinel nodes are either all `Data` or +// all `Blocked` (requests for data from blocked threads). +#[derive(Debug)] +pub struct Queue { + head: CachePadded>>, + tail: CachePadded>>, +} + +struct Node { + /// The slot in which a value of type `T` can be stored. + /// + /// The type of `data` is `MaybeUninit` because a `Node` doesn't always contain a `T`. + /// For example, the sentinel node in a queue never contains a value: its slot is always empty. + /// Other nodes start their life with a push operation and contain a value until it gets popped + /// out. After that such empty nodes get added to the collector for destruction. + data: MaybeUninit, + + next: Atomic>, +} + +// Any particular `T` should never be accessed concurrently, so no need for `Sync`. +unsafe impl Sync for Queue {} +unsafe impl Send for Queue {} + +impl Queue { + /// Create a new, empty queue. + pub fn new() -> Queue { + let q = Queue { + head: CachePadded::new(Atomic::null()), + tail: CachePadded::new(Atomic::null()), + }; + let sentinel = Owned::new(Node { + data: MaybeUninit::uninit(), + next: Atomic::null(), + }); + unsafe { + let guard = unprotected(); + let sentinel = sentinel.into_shared(guard); + q.head.store(sentinel, Relaxed); + q.tail.store(sentinel, Relaxed); + q + } + } + + /// Attempts to atomically place `n` into the `next` pointer of `onto`, and returns `true` on + /// success. The queue's `tail` pointer may be updated. + #[inline(always)] + fn push_internal( + &self, + onto: Shared<'_, Node>, + new: Shared<'_, Node>, + guard: &Guard, + ) -> bool { + // is `onto` the actual tail? + let o = unsafe { onto.deref() }; + let next = o.next.load(Acquire, guard); + if unsafe { next.as_ref().is_some() } { + // if not, try to "help" by moving the tail pointer forward + let _ = self.tail.compare_and_set(onto, next, Release, guard); + false + } else { + // looks like the actual tail; attempt to link in `n` + let result = o + .next + .compare_and_set(Shared::null(), new, Release, guard) + .is_ok(); + if result { + // try to move the tail pointer forward + let _ = self.tail.compare_and_set(onto, new, Release, guard); + } + result + } + } + + /// Adds `t` to the back of the queue, possibly waking up threads blocked on `pop`. + pub fn push(&self, t: T, guard: &Guard) { + let new = Owned::new(Node { + data: MaybeUninit::new(t), + next: Atomic::null(), + }); + let new = Owned::into_shared(new, guard); + + loop { + // We push onto the tail, so we'll start optimistically by looking there first. + let tail = self.tail.load(Acquire, guard); + + // Attempt to push onto the `tail` snapshot; fails if `tail.next` has changed. + if self.push_internal(tail, new, guard) { + break; + } + } + } + + /// Attempts to pop a data node. `Ok(None)` if queue is empty; `Err(())` if lost race to pop. + #[inline(always)] + fn pop_internal(&self, guard: &Guard) -> Result, ()> { + let head = self.head.load(Acquire, guard); + let h = unsafe { head.deref() }; + let next = h.next.load(Acquire, guard); + match unsafe { next.as_ref() } { + Some(n) => unsafe { + self.head + .compare_and_set(head, next, Release, guard) + .map(|_| { + let tail = self.tail.load(Relaxed, guard); + // Advance the tail so that we don't retire a pointer to a reachable node. + if head == tail { + let _ = self.tail.compare_and_set(tail, next, Release, guard); + } + guard.defer_destroy(head); + // TODO: Replace with MaybeUninit::read when api is stable + Some(n.data.as_ptr().read()) + }) + .map_err(|_| ()) + }, + None => Ok(None), + } + } + + /// Attempts to pop a data node, if the data satisfies the given condition. `Ok(None)` if queue + /// is empty or the data does not satisfy the condition; `Err(())` if lost race to pop. + #[inline(always)] + fn pop_if_internal(&self, condition: F, guard: &Guard) -> Result, ()> + where + T: Sync, + F: Fn(&T) -> bool, + { + let head = self.head.load(Acquire, guard); + let h = unsafe { head.deref() }; + let next = h.next.load(Acquire, guard); + match unsafe { next.as_ref() } { + Some(n) if condition(unsafe { &*n.data.as_ptr() }) => unsafe { + self.head + .compare_and_set(head, next, Release, guard) + .map(|_| { + let tail = self.tail.load(Relaxed, guard); + // Advance the tail so that we don't retire a pointer to a reachable node. + if head == tail { + let _ = self.tail.compare_and_set(tail, next, Release, guard); + } + guard.defer_destroy(head); + Some(n.data.as_ptr().read()) + }) + .map_err(|_| ()) + }, + None | Some(_) => Ok(None), + } + } + + /// Attempts to dequeue from the front. + /// + /// Returns `None` if the queue is observed to be empty. + pub fn try_pop(&self, guard: &Guard) -> Option { + loop { + if let Ok(head) = self.pop_internal(guard) { + return head; + } + } + } + + /// Attempts to dequeue from the front, if the item satisfies the given condition. + /// + /// Returns `None` if the queue is observed to be empty, or the head does not satisfy the given + /// condition. + pub fn try_pop_if(&self, condition: F, guard: &Guard) -> Option + where + T: Sync, + F: Fn(&T) -> bool, + { + loop { + if let Ok(head) = self.pop_if_internal(&condition, guard) { + return head; + } + } + } +} + +impl Drop for Queue { + fn drop(&mut self) { + unsafe { + let guard = unprotected(); + + while self.try_pop(guard).is_some() {} + + // Destroy the remaining sentinel node. + let sentinel = self.head.load(Relaxed, guard); + drop(sentinel.into_owned()); + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::pin; + use crossbeam_utils::thread; + + struct Queue { + queue: super::Queue, + } + + impl Queue { + pub fn new() -> Queue { + Queue { + queue: super::Queue::new(), + } + } + + pub fn push(&self, t: T) { + let guard = &pin(); + self.queue.push(t, guard); + } + + pub fn is_empty(&self) -> bool { + let guard = &pin(); + let head = self.queue.head.load(Acquire, guard); + let h = unsafe { head.deref() }; + h.next.load(Acquire, guard).is_null() + } + + pub fn try_pop(&self) -> Option { + let guard = &pin(); + self.queue.try_pop(guard) + } + + pub fn pop(&self) -> T { + loop { + match self.try_pop() { + None => continue, + Some(t) => return t, + } + } + } + } + + const CONC_COUNT: i64 = 1000000; + + #[test] + fn push_try_pop_1() { + let q: Queue = Queue::new(); + assert!(q.is_empty()); + q.push(37); + assert!(!q.is_empty()); + assert_eq!(q.try_pop(), Some(37)); + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_2() { + let q: Queue = Queue::new(); + assert!(q.is_empty()); + q.push(37); + q.push(48); + assert_eq!(q.try_pop(), Some(37)); + assert!(!q.is_empty()); + assert_eq!(q.try_pop(), Some(48)); + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_many_seq() { + let q: Queue = Queue::new(); + assert!(q.is_empty()); + for i in 0..200 { + q.push(i) + } + assert!(!q.is_empty()); + for i in 0..200 { + assert_eq!(q.try_pop(), Some(i)); + } + assert!(q.is_empty()); + } + + #[test] + fn push_pop_1() { + let q: Queue = Queue::new(); + assert!(q.is_empty()); + q.push(37); + assert!(!q.is_empty()); + assert_eq!(q.pop(), 37); + assert!(q.is_empty()); + } + + #[test] + fn push_pop_2() { + let q: Queue = Queue::new(); + q.push(37); + q.push(48); + assert_eq!(q.pop(), 37); + assert_eq!(q.pop(), 48); + } + + #[test] + fn push_pop_many_seq() { + let q: Queue = Queue::new(); + assert!(q.is_empty()); + for i in 0..200 { + q.push(i) + } + assert!(!q.is_empty()); + for i in 0..200 { + assert_eq!(q.pop(), i); + } + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_many_spsc() { + let q: Queue = Queue::new(); + assert!(q.is_empty()); + + thread::scope(|scope| { + scope.spawn(|_| { + let mut next = 0; + + while next < CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert_eq!(elem, next); + next += 1; + } + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }) + .unwrap(); + } + + #[test] + fn push_try_pop_many_spmc() { + fn recv(_t: i32, q: &Queue) { + let mut cur = -1; + for _i in 0..CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert!(elem > cur); + cur = elem; + + if cur == CONC_COUNT - 1 { + break; + } + } + } + } + + let q: Queue = Queue::new(); + assert!(q.is_empty()); + thread::scope(|scope| { + for i in 0..3 { + let q = &q; + scope.spawn(move |_| recv(i, q)); + } + + scope.spawn(|_| { + for i in 0..CONC_COUNT { + q.push(i); + } + }); + }) + .unwrap(); + } + + #[test] + fn push_try_pop_many_mpmc() { + enum LR { + Left(i64), + Right(i64), + } + + let q: Queue = Queue::new(); + assert!(q.is_empty()); + + thread::scope(|scope| { + for _t in 0..2 { + scope.spawn(|_| { + for i in CONC_COUNT - 1..CONC_COUNT { + q.push(LR::Left(i)) + } + }); + scope.spawn(|_| { + for i in CONC_COUNT - 1..CONC_COUNT { + q.push(LR::Right(i)) + } + }); + scope.spawn(|_| { + let mut vl = vec![]; + let mut vr = vec![]; + for _i in 0..CONC_COUNT { + match q.try_pop() { + Some(LR::Left(x)) => vl.push(x), + Some(LR::Right(x)) => vr.push(x), + _ => {} + } + } + + let mut vl2 = vl.clone(); + let mut vr2 = vr.clone(); + vl2.sort(); + vr2.sort(); + + assert_eq!(vl, vl2); + assert_eq!(vr, vr2); + }); + } + }) + .unwrap(); + } + + #[test] + fn push_pop_many_spsc() { + let q: Queue = Queue::new(); + + thread::scope(|scope| { + scope.spawn(|_| { + let mut next = 0; + while next < CONC_COUNT { + assert_eq!(q.pop(), next); + next += 1; + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }) + .unwrap(); + assert!(q.is_empty()); + } + + #[test] + fn is_empty_dont_pop() { + let q: Queue = Queue::new(); + q.push(20); + q.push(20); + assert!(!q.is_empty()); + assert!(!q.is_empty()); + assert!(q.try_pop().is_some()); + } +} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-queue-0.2.2/.cargo-checksum.json deleted file mode 100644 index 1957371..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"cd81bbb3201007b7a9e37730501955e44808c48e79738f3f3a033eb507ee578d","Cargo.toml":"6bc61dc53eba6a181cc0a468063a1ad1d60180a171188297bdc97d6b08b1d3d4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"abb1905b1c2b7db73902e6c328d332d82f3797d7fab61e6fc1c2fc366b132014","README.md":"a4cf719c04f69cc7a7016242875dcf0f74e4ca710e33df372e21275de08170c2","src/array_queue.rs":"eb12dbe04e8b49a18e85f2a487222e8ca297fd790d40beeeb5fc21ba58560937","src/err.rs":"1cf3b3c12b7de3be7b008dbf43769b585fde832f8a0af526abded52fcb08c41a","src/lib.rs":"b4b2afba1dfb79a4797f5a3a961e17022bfcf9e0bb20423086f501f63b9dc9a2","src/seg_queue.rs":"de3d23f0824ff6c81cc0ccfe7b22735a7533906906736e9e92096151a21ec81a","tests/array_queue.rs":"18fca619e075971b53b6286ac561b7fd3c841039e02dd17c04d16ca0065bfa71","tests/seg_queue.rs":"80eb0ae14911edbaacd98e54b2b97f772bade14a9a892bbb55ce403525e59a99"},"package":"ab6bffe714b6bb07e42f201352c34f51fefd355ace793f9e638ebd52d23f98d2"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/BUILD.bazel b/third_party/cargo/vendor/crossbeam-queue-0.2.2/BUILD.bazel deleted file mode 100644 index 02f3ab5..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/BUILD.bazel +++ /dev/null @@ -1,62 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # MIT from expression "MIT OR Apache-2.0" -]) - -# Generated Targets - -rust_library( - name = "crossbeam_queue", - srcs = glob(["**/*.rs"]), - crate_features = [ - "alloc", - "default", - "std", - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2018", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.2.2", - # buildifier: leave-alone - deps = [ - "//third_party/cargo/vendor/cfg-if-0.1.10:cfg_if", - "//third_party/cargo/vendor/crossbeam-utils-0.7.2:crossbeam_utils", - ], -) - -# Unsupported target "array_queue" with type "test" omitted - -# Unsupported target "seg_queue" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-queue-0.2.2/CHANGELOG.md deleted file mode 100644 index 9ac6d48..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/CHANGELOG.md +++ /dev/null @@ -1,24 +0,0 @@ -# Version 0.2.2 - -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) - -# Version 0.2.1 - -- Add `no_std` support. - -# Version 0.2.0 - -- Bump the minimum required version to 1.28. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.1.2 - -- Update `crossbeam-utils` to `0.6.5`. - -# Version 0.1.1 - -- Update `crossbeam-utils` to `0.6.4`. - -# Version 0.1.0 - -- Initial version with `ArrayQueue` and `SegQueue`. diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/Cargo.toml b/third_party/cargo/vendor/crossbeam-queue-0.2.2/Cargo.toml deleted file mode 100644 index ebb7348..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "crossbeam-queue" -version = "0.2.2" -authors = ["The Crossbeam Project Developers"] -description = "Concurrent queues" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" -documentation = "https://docs.rs/crossbeam-queue" -readme = "README.md" -keywords = ["queue", "mpmc", "lock-free", "producer", "consumer"] -categories = ["concurrency", "data-structures"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" -[dependencies.cfg-if] -version = "0.1.10" - -[dependencies.crossbeam-utils] -version = "0.7" -default-features = false -[dev-dependencies.rand] -version = "0.7.3" - -[features] -alloc = [] -default = ["std"] -nightly = [] -std = ["alloc", "crossbeam-utils/std"] diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/README.md b/third_party/cargo/vendor/crossbeam-queue-0.2.2/README.md deleted file mode 100644 index 008889d..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Crossbeam Queue - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam-queue.svg)]( -https://crates.io/crates/crossbeam-queue) -[![Documentation](https://docs.rs/crossbeam-queue/badge.svg)]( -https://docs.rs/crossbeam-queue) -[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) - -This crate provides concurrent queues that can be shared among threads: - -* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. - -[`ArrayQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.ArrayQueue.html -[`SegQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.SegQueue.html - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-queue = "0.2" -``` - -## Compatibility - -Crossbeam Queue supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.36. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -#### Third party software - -This product includes copies and modifications of software developed by third parties: - -* [src/array_queue.rs](src/array_queue.rs) is based on - [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) - by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. - -See the source code files for more details. - -Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/array_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/array_queue.rs deleted file mode 100644 index eb97e8e..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/array_queue.rs +++ /dev/null @@ -1,437 +0,0 @@ -//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. -//! -//! Source: -//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue -//! -//! Copyright & License: -//! - Copyright (c) 2010-2011 Dmitry Vyukov -//! - Simplified BSD License and Apache License, Version 2.0 -//! - http://www.1024cores.net/home/code-license - -use alloc::vec::Vec; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::mem::{self, MaybeUninit}; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -use crate::err::{PopError, PushError}; - -/// A slot in a queue. -struct Slot { - /// The current stamp. - /// - /// If the stamp equals the tail, this node will be next written to. If it equals head + 1, - /// this node will be next read from. - stamp: AtomicUsize, - - /// The value in this slot. - value: UnsafeCell>, -} - -/// A bounded multi-producer multi-consumer queue. -/// -/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed -/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an -/// element into a full queue will fail. Having a buffer allocated upfront makes this queue a bit -/// faster than [`SegQueue`]. -/// -/// [`SegQueue`]: struct.SegQueue.html -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::{ArrayQueue, PushError}; -/// -/// let q = ArrayQueue::new(2); -/// -/// assert_eq!(q.push('a'), Ok(())); -/// assert_eq!(q.push('b'), Ok(())); -/// assert_eq!(q.push('c'), Err(PushError('c'))); -/// assert_eq!(q.pop(), Ok('a')); -/// ``` -pub struct ArrayQueue { - /// The head of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are popped from the head of the queue. - head: CachePadded, - - /// The tail of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are pushed into the tail of the queue. - tail: CachePadded, - - /// The buffer holding slots. - buffer: *mut Slot, - - /// The queue capacity. - cap: usize, - - /// A stamp with the value of `{ lap: 1, index: 0 }`. - one_lap: usize, - - /// Indicates that dropping an `ArrayQueue` may drop elements of type `T`. - _marker: PhantomData, -} - -unsafe impl Sync for ArrayQueue {} -unsafe impl Send for ArrayQueue {} - -impl ArrayQueue { - /// Creates a new bounded queue with the given capacity. - /// - /// # Panics - /// - /// Panics if the capacity is zero. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// ``` - pub fn new(cap: usize) -> ArrayQueue { - assert!(cap > 0, "capacity must be non-zero"); - - // Head is initialized to `{ lap: 0, index: 0 }`. - // Tail is initialized to `{ lap: 0, index: 0 }`. - let head = 0; - let tail = 0; - - // Allocate a buffer of `cap` slots initialized - // with stamps. - let buffer = { - let mut v: Vec> = (0..cap) - .map(|i| { - // Set the stamp to `{ lap: 0, index: i }`. - Slot { - stamp: AtomicUsize::new(i), - value: UnsafeCell::new(MaybeUninit::uninit()), - } - }) - .collect(); - let ptr = v.as_mut_ptr(); - mem::forget(v); - ptr - }; - - // One lap is the smallest power of two greater than `cap`. - let one_lap = (cap + 1).next_power_of_two(); - - ArrayQueue { - buffer, - cap, - one_lap, - head: CachePadded::new(AtomicUsize::new(head)), - tail: CachePadded::new(AtomicUsize::new(tail)), - _marker: PhantomData, - } - } - - /// Attempts to push an element into the queue. - /// - /// If the queue is full, the element is returned back as an error. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PushError}; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert_eq!(q.push(10), Ok(())); - /// assert_eq!(q.push(20), Err(PushError(20))); - /// ``` - pub fn push(&self, value: T) -> Result<(), PushError> { - let backoff = Backoff::new(); - let mut tail = self.tail.load(Ordering::Relaxed); - - loop { - // Deconstruct the tail. - let index = tail & (self.one_lap - 1); - let lap = tail & !(self.one_lap - 1); - - // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the tail and the stamp match, we may attempt to push. - if tail == stamp { - let new_tail = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - tail + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Try moving the tail. - match self.tail.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Write the value into the slot and update the stamp. - unsafe { - slot.value.get().write(MaybeUninit::new(value)); - } - slot.stamp.store(tail + 1, Ordering::Release); - return Ok(()); - } - Err(t) => { - tail = t; - backoff.spin(); - } - } - } else if stamp.wrapping_add(self.one_lap) == tail + 1 { - atomic::fence(Ordering::SeqCst); - let head = self.head.load(Ordering::Relaxed); - - // If the head lags one lap behind the tail as well... - if head.wrapping_add(self.one_lap) == tail { - // ...then the queue is full. - return Err(PushError(value)); - } - - backoff.spin(); - tail = self.tail.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - tail = self.tail.load(Ordering::Relaxed); - } - } - } - - /// Attempts to pop an element from the queue. - /// - /// If the queue is empty, an error is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::new(1); - /// assert_eq!(q.push(10), Ok(())); - /// - /// assert_eq!(q.pop(), Ok(10)); - /// assert_eq!(q.pop(), Err(PopError)); - /// ``` - pub fn pop(&self) -> Result { - let backoff = Backoff::new(); - let mut head = self.head.load(Ordering::Relaxed); - - loop { - // Deconstruct the head. - let index = head & (self.one_lap - 1); - let lap = head & !(self.one_lap - 1); - - // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the the stamp is ahead of the head by 1, we may attempt to pop. - if head + 1 == stamp { - let new = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Try moving the head. - match self.head.compare_exchange_weak( - head, - new, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Read the value from the slot and update the stamp. - let msg = unsafe { slot.value.get().read().assume_init() }; - slot.stamp - .store(head.wrapping_add(self.one_lap), Ordering::Release); - return Ok(msg); - } - Err(h) => { - head = h; - backoff.spin(); - } - } - } else if stamp == head { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.load(Ordering::Relaxed); - - // If the tail equals the head, that means the channel is empty. - if tail == head { - return Err(PopError); - } - - backoff.spin(); - head = self.head.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - head = self.head.load(Ordering::Relaxed); - } - } - } - - /// Returns the capacity of the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// - /// assert_eq!(q.capacity(), 100); - /// ``` - pub fn capacity(&self) -> usize { - self.cap - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(100); - /// - /// assert!(q.is_empty()); - /// q.push(1).unwrap(); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.load(Ordering::SeqCst); - let tail = self.tail.load(Ordering::SeqCst); - - // Is the tail lagging one lap behind head? - // Is the tail equal to the head? - // - // Note: If the head changes just before we load the tail, that means there was a moment - // when the channel was not empty, so it is safe to just return `false`. - tail == head - } - - /// Returns `true` if the queue is full. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert!(!q.is_full()); - /// q.push(1).unwrap(); - /// assert!(q.is_full()); - /// ``` - pub fn is_full(&self) -> bool { - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // Is the head lagging one lap behind tail? - // - // Note: If the tail changes just before we load the head, that means there was a moment - // when the queue was not full, so it is safe to just return `false`. - head.wrapping_add(self.one_lap) == tail - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(100); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10).unwrap(); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20).unwrap(); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail, then load the head. - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // If the tail didn't change, we've got consistent values to work with. - if self.tail.load(Ordering::SeqCst) == tail { - let hix = head & (self.one_lap - 1); - let tix = tail & (self.one_lap - 1); - - return if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if tail == head { - 0 - } else { - self.cap - }; - } - } - } -} - -impl Drop for ArrayQueue { - fn drop(&mut self) { - // Get the index of the head. - let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1); - - // Loop over all slots that hold a message and drop them. - for i in 0..self.len() { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { - hix + i - } else { - hix + i - self.cap - }; - - unsafe { - let p = { - let slot = &mut *self.buffer.add(index); - let value = &mut *slot.value.get(); - value.as_mut_ptr() - }; - p.drop_in_place(); - } - } - - // Finally, deallocate the buffer, but don't run any destructors. - unsafe { - Vec::from_raw_parts(self.buffer, 0, self.cap); - } - } -} - -impl fmt::Debug for ArrayQueue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("ArrayQueue { .. }") - } -} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/err.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/err.rs deleted file mode 100644 index 44fe916..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/err.rs +++ /dev/null @@ -1,39 +0,0 @@ -use core::fmt; - -/// Error which occurs when popping from an empty queue. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PopError; - -impl fmt::Debug for PopError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "PopError".fmt(f) - } -} - -impl fmt::Display for PopError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "popping from an empty queue".fmt(f) - } -} - -#[cfg(feature = "std")] -impl ::std::error::Error for PopError {} - -/// Error which occurs when pushing into a full queue. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PushError(pub T); - -impl fmt::Debug for PushError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "PushError(..)".fmt(f) - } -} - -impl fmt::Display for PushError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "pushing into a full queue".fmt(f) - } -} - -#[cfg(feature = "std")] -impl ::std::error::Error for PushError {} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/lib.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/lib.rs deleted file mode 100644 index 9d29b77..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Concurrent queues. -//! -//! This crate provides concurrent queues that can be shared among threads: -//! -//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. -//! -//! [`ArrayQueue`]: struct.ArrayQueue.html -//! [`SegQueue`]: struct.SegQueue.html - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] -#![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] - -#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] -cfg_if::cfg_if! { - if #[cfg(feature = "alloc")] { - extern crate alloc; - - mod array_queue; - mod err; - mod seg_queue; - - pub use self::array_queue::ArrayQueue; - pub use self::err::{PopError, PushError}; - pub use self::seg_queue::SegQueue; - } -} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/seg_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/seg_queue.rs deleted file mode 100644 index 8dd1547..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/src/seg_queue.rs +++ /dev/null @@ -1,488 +0,0 @@ -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::mem::MaybeUninit; -use core::ptr; -use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -use crate::err::PopError; - -// Bits indicating the state of a slot: -// * If a value has been written into the slot, `WRITE` is set. -// * If a value has been read from the slot, `READ` is set. -// * If the block is being destroyed, `DESTROY` is set. -const WRITE: usize = 1; -const READ: usize = 2; -const DESTROY: usize = 4; - -// Each block covers one "lap" of indices. -const LAP: usize = 32; -// The maximum number of values a block can hold. -const BLOCK_CAP: usize = LAP - 1; -// How many lower bits are reserved for metadata. -const SHIFT: usize = 1; -// Indicates that the block is not the last one. -const HAS_NEXT: usize = 1; - -/// A slot in a block. -struct Slot { - /// The value. - value: UnsafeCell>, - - /// The state of the slot. - state: AtomicUsize, -} - -impl Slot { - /// Waits until a value is written into the slot. - fn wait_write(&self) { - let backoff = Backoff::new(); - while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); - } - } -} - -/// A block in a linked list. -/// -/// Each block in the list can hold up to `BLOCK_CAP` values. -struct Block { - /// The next block in the linked list. - next: AtomicPtr>, - - /// Slots for values. - slots: [Slot; BLOCK_CAP], -} - -impl Block { - /// Creates an empty block that starts at `start_index`. - fn new() -> Block { - // SAFETY: This is safe because: - // [1] `Block::next` (AtomicPtr) may be safely zero initialized. - // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. - // [3] `Slot::value` (UnsafeCell) may be safely zero initialized because it - // holds a MaybeUninit. - // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } - } - - /// Waits until the next pointer is set. - fn wait_next(&self) -> *mut Block { - let backoff = Backoff::new(); - loop { - let next = self.next.load(Ordering::Acquire); - if !next.is_null() { - return next; - } - backoff.snooze(); - } - } - - /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. - unsafe fn destroy(this: *mut Block, start: usize) { - // It is not necessary to set the `DESTROY` bit in the last slot because that slot has - // begun destruction of the block. - for i in start..BLOCK_CAP - 1 { - let slot = (*this).slots.get_unchecked(i); - - // Mark the `DESTROY` bit if a thread is still using the slot. - if slot.state.load(Ordering::Acquire) & READ == 0 - && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 - { - // If a thread is still using the slot, it will continue destruction of the block. - return; - } - } - - // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); - } -} - -/// A position in a queue. -struct Position { - /// The index in the queue. - index: AtomicUsize, - - /// The block in the linked list. - block: AtomicPtr>, -} - -/// An unbounded multi-producer multi-consumer queue. -/// -/// This queue is implemented as a linked list of segments, where each segment is a small buffer -/// that can hold a handful of elements. There is no limit to how many elements can be in the queue -/// at a time. However, since segments need to be dynamically allocated as elements get pushed, -/// this queue is somewhat slower than [`ArrayQueue`]. -/// -/// [`ArrayQueue`]: struct.ArrayQueue.html -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::{PopError, SegQueue}; -/// -/// let q = SegQueue::new(); -/// -/// q.push('a'); -/// q.push('b'); -/// -/// assert_eq!(q.pop(), Ok('a')); -/// assert_eq!(q.pop(), Ok('b')); -/// assert_eq!(q.pop(), Err(PopError)); -/// ``` -pub struct SegQueue { - /// The head of the queue. - head: CachePadded>, - - /// The tail of the queue. - tail: CachePadded>, - - /// Indicates that dropping a `SegQueue` may drop values of type `T`. - _marker: PhantomData, -} - -unsafe impl Send for SegQueue {} -unsafe impl Sync for SegQueue {} - -impl SegQueue { - /// Creates a new unbounded queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::::new(); - /// ``` - pub fn new() -> SegQueue { - SegQueue { - head: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - tail: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - _marker: PhantomData, - } - } - - /// Pushes an element into the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// q.push(20); - /// ``` - pub fn push(&self, value: T) { - let backoff = Backoff::new(); - let mut tail = self.tail.index.load(Ordering::Acquire); - let mut block = self.tail.block.load(Ordering::Acquire); - let mut next_block = None; - - loop { - // Calculate the offset of the index into the block. - let offset = (tail >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - - // If we're going to have to install the next block, allocate it in advance in order to - // make the wait for other threads as short as possible. - if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::::new())); - } - - // If this is the first push operation, we need to allocate the first block. - if block.is_null() { - let new = Box::into_raw(Box::new(Block::::new())); - - if self - .tail - .block - .compare_and_swap(block, new, Ordering::Release) - == block - { - self.head.block.store(new, Ordering::Release); - block = new; - } else { - next_block = unsafe { Some(Box::from_raw(new)) }; - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - } - - let new_tail = tail + (1 << SHIFT); - - // Try advancing the tail forward. - match self.tail.index.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, install the next one. - if offset + 1 == BLOCK_CAP { - let next_block = Box::into_raw(next_block.unwrap()); - let next_index = new_tail.wrapping_add(1 << SHIFT); - - self.tail.block.store(next_block, Ordering::Release); - self.tail.index.store(next_index, Ordering::Release); - (*block).next.store(next_block, Ordering::Release); - } - - // Write the value into the slot. - let slot = (*block).slots.get_unchecked(offset); - slot.value.get().write(MaybeUninit::new(value)); - slot.state.fetch_or(WRITE, Ordering::Release); - - return; - }, - Err(t) => { - tail = t; - block = self.tail.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Pops an element from the queue. - /// - /// If the queue is empty, an error is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{PopError, SegQueue}; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// assert_eq!(q.pop(), Ok(10)); - /// assert_eq!(q.pop(), Err(PopError)); - /// ``` - pub fn pop(&self) -> Result { - let backoff = Backoff::new(); - let mut head = self.head.index.load(Ordering::Acquire); - let mut block = self.head.block.load(Ordering::Acquire); - - loop { - // Calculate the offset of the index into the block. - let offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - let mut new_head = head + (1 << SHIFT); - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return Err(PopError); - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - } - } - - // The block can be null here only if the first push operation is in progress. In that - // case, just wait until it gets initialized. - if block.is_null() { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - // Try moving the head index forward. - match self.head.index.compare_exchange_weak( - head, - new_head, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, move to the next one. - if offset + 1 == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Read the value. - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let value = slot.value.get().read().assume_init(); - - // Destroy the block if we've reached the end, or if another thread wanted to - // destroy but couldn't because we were busy reading from the slot. - if offset + 1 == BLOCK_CAP { - Block::destroy(block, 0); - } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset + 1); - } - - return Ok(value); - }, - Err(h) => { - head = h; - block = self.head.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// assert!(q.is_empty()); - /// q.push(1); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.index.load(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::SeqCst); - head >> SHIFT == tail >> SHIFT - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail index, then load the head index. - let mut tail = self.tail.index.load(Ordering::SeqCst); - let mut head = self.head.index.load(Ordering::SeqCst); - - // If the tail index didn't change, we've got consistent indices to work with. - if self.tail.index.load(Ordering::SeqCst) == tail { - // Erase the lower bits. - tail &= !((1 << SHIFT) - 1); - head &= !((1 << SHIFT) - 1); - - // Fix up indices if they fall onto block ends. - if (tail >> SHIFT) & (LAP - 1) == LAP - 1 { - tail = tail.wrapping_add(1 << SHIFT); - } - if (head >> SHIFT) & (LAP - 1) == LAP - 1 { - head = head.wrapping_add(1 << SHIFT); - } - - // Rotate indices so that head falls into the first block. - let lap = (head >> SHIFT) / LAP; - tail = tail.wrapping_sub((lap * LAP) << SHIFT); - head = head.wrapping_sub((lap * LAP) << SHIFT); - - // Remove the lower bits. - tail >>= SHIFT; - head >>= SHIFT; - - // Return the difference minus the number of blocks between tail and head. - return tail - head - tail / LAP; - } - } - } -} - -impl Drop for SegQueue { - fn drop(&mut self) { - let mut head = self.head.index.load(Ordering::Relaxed); - let mut tail = self.tail.index.load(Ordering::Relaxed); - let mut block = self.head.block.load(Ordering::Relaxed); - - // Erase the lower bits. - head &= !((1 << SHIFT) - 1); - tail &= !((1 << SHIFT) - 1); - - unsafe { - // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. - while head != tail { - let offset = (head >> SHIFT) % LAP; - - if offset < BLOCK_CAP { - // Drop the value in the slot. - let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.value.get(); - p.as_mut_ptr().drop_in_place(); - } else { - // Deallocate the block and move to the next one. - let next = (*block).next.load(Ordering::Relaxed); - drop(Box::from_raw(block)); - block = next; - } - - head = head.wrapping_add(1 << SHIFT); - } - - // Deallocate the last remaining block. - if !block.is_null() { - drop(Box::from_raw(block)); - } - } - } -} - -impl fmt::Debug for SegQueue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("SegQueue { .. }") - } -} - -impl Default for SegQueue { - fn default() -> SegQueue { - SegQueue::new() - } -} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/tests/array_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.2/tests/array_queue.rs deleted file mode 100644 index 6dd6ce2..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/tests/array_queue.rs +++ /dev/null @@ -1,250 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::ArrayQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = ArrayQueue::new(1); - - q.push(7).unwrap(); - assert_eq!(q.pop(), Ok(7)); - - q.push(8).unwrap(); - assert_eq!(q.pop(), Ok(8)); - assert!(q.pop().is_err()); -} - -#[test] -fn capacity() { - for i in 1..10 { - let q = ArrayQueue::::new(i); - assert_eq!(q.capacity(), i); - } -} - -#[test] -#[should_panic(expected = "capacity must be non-zero")] -fn zero_capacity() { - let _ = ArrayQueue::::new(0); -} - -#[test] -fn len_empty_full() { - let q = ArrayQueue::new(2); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); - assert_eq!(q.is_full(), false); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), false); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 2); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), true); - - q.pop().unwrap(); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), false); -} - -#[test] -fn len() { - const COUNT: usize = 25_000; - const CAP: usize = 1000; - - let q = ArrayQueue::new(CAP); - assert_eq!(q.len(), 0); - - for _ in 0..CAP / 10 { - for i in 0..50 { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - } - assert_eq!(q.len(), 0); - - for i in 0..CAP { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for _ in 0..CAP { - q.pop().unwrap(); - } - assert_eq!(q.len(), 0); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - let len = q.len(); - assert!(len <= CAP); - } - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - let len = q.len(); - assert!(len <= CAP); - } - }); - }) - .unwrap(); - assert_eq!(q.len(), 0); -} - -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = ArrayQueue::new(3); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_err()); - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - }) - .unwrap(); -} - -#[test] -fn mpmc() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Ok(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn drops() { - const RUNS: usize = 100; - - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..RUNS { - let steps = rng.gen_range(0, 10_000); - let additional = rng.gen_range(0, 50); - - DROPS.store(0, Ordering::SeqCst); - let q = ArrayQueue::new(50); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_err() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - while q.push(DropCounter).is_err() { - DROPS.fetch_sub(1, Ordering::SeqCst); - } - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter).unwrap(); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} - -#[test] -fn linearizable() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::new(THREADS); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - while q.push(0).is_err() {} - q.pop().unwrap(); - } - }); - } - }) - .unwrap(); -} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/tests/seg_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.2/tests/seg_queue.rs deleted file mode 100644 index b8ffbd3..0000000 --- a/third_party/cargo/vendor/crossbeam-queue-0.2.2/tests/seg_queue.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::SegQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = SegQueue::new(); - q.push(7); - assert_eq!(q.pop(), Ok(7)); - - q.push(8); - assert_eq!(q.pop(), Ok(8)); - assert!(q.pop().is_err()); -} - -#[test] -fn len_empty_full() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); - - q.push(()); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - - q.pop().unwrap(); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); -} - -#[test] -fn len() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - - for i in 0..50 { - q.push(i); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - - assert_eq!(q.len(), 0); -} - -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_err()); - }); - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - }) - .unwrap(); -} - -#[test] -fn mpmc() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = SegQueue::::new(); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Ok(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn drops() { - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..100 { - let steps = rng.gen_range(0, 10_000); - let additional = rng.gen_range(0, 1000); - - DROPS.store(0, Ordering::SeqCst); - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_err() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - q.push(DropCounter); - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-queue-0.2.3/.cargo-checksum.json new file mode 100644 index 0000000..b0d2114 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"fd132a0c0418817ad83e67f46762a13e8c210ce6e94293abfa902361d99b953d","Cargo.toml":"49f1e746f6258de6e2b2127cd974a54735b08d565068b4079378a68eb73a5946","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"abb1905b1c2b7db73902e6c328d332d82f3797d7fab61e6fc1c2fc366b132014","README.md":"b487d2d9d9cf9726fbf3b5cf736ddc363f8d1e1410a0a4020dda27c4df72c627","src/array_queue.rs":"02d3deea53652d6fadba3bb4236324262776242176f487688dcf624b379ad500","src/err.rs":"cde063a29dc8887d4c3bd0994f7aab08879841d94c61ecf104a8a85f2c436302","src/lib.rs":"a1331aa4f2d67b4e634667f225c63d55b234802bd1ff72a485d2d56a08eab521","src/seg_queue.rs":"732b5b032313329e39d9c08cf6e63d2926950d645467983fc62e7cabb3cbe330","tests/array_queue.rs":"3faa35bbe2acb3dabdfab5e81860a19e0237c57513420bbb9afe0cb89ac25909","tests/seg_queue.rs":"885ea52ce2c5d1fa9b4265250957d51ffa3f0781d57b01d28cb871371e32ac92"},"package":"774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/BUILD.bazel b/third_party/cargo/vendor/crossbeam-queue-0.2.3/BUILD.bazel new file mode 100644 index 0000000..d08f695 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/BUILD.bazel @@ -0,0 +1,62 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR (Apache-2.0 AND BSD-2-Clause)" +]) + +# Generated Targets + +rust_library( + name = "crossbeam_queue", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.2.3", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/cfg-if-0.1.10:cfg_if", + "//third_party/cargo/vendor/crossbeam-utils-0.7.2:crossbeam_utils", + "//third_party/cargo/vendor/maybe-uninit-2.0.0:maybe_uninit", + ], +) + +# Unsupported target "array_queue" with type "test" omitted + +# Unsupported target "seg_queue" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-queue-0.2.3/CHANGELOG.md new file mode 100644 index 0000000..e44d1f9 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/CHANGELOG.md @@ -0,0 +1,28 @@ +# Version 0.2.3 + +- Fix bug in release (yanking 0.2.2) + +# Version 0.2.2 + +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) + +# Version 0.2.1 + +- Add `no_std` support. + +# Version 0.2.0 + +- Bump the minimum required version to 1.28. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.1.2 + +- Update `crossbeam-utils` to `0.6.5`. + +# Version 0.1.1 + +- Update `crossbeam-utils` to `0.6.4`. + +# Version 0.1.0 + +- Initial version with `ArrayQueue` and `SegQueue`. diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/Cargo.toml b/third_party/cargo/vendor/crossbeam-queue-0.2.3/Cargo.toml new file mode 100644 index 0000000..c03e35b --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crossbeam-queue" +version = "0.2.3" +authors = ["The Crossbeam Project Developers"] +description = "Concurrent queues" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" +documentation = "https://docs.rs/crossbeam-queue" +readme = "README.md" +keywords = ["queue", "mpmc", "lock-free", "producer", "consumer"] +categories = ["concurrency", "data-structures"] +license = "MIT/Apache-2.0 AND BSD-2-Clause" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dependencies.cfg-if] +version = "0.1.2" + +[dependencies.crossbeam-utils] +version = "0.7" +default-features = false + +[dependencies.maybe-uninit] +version = "2.0.0" +[dev-dependencies.rand] +version = "0.6" + +[features] +alloc = ["crossbeam-utils/alloc"] +default = ["std"] +std = ["crossbeam-utils/std"] diff --git a/third_party/cargo/vendor/derivative-2.1.1/LICENSE-APACHE b/third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/derivative-2.1.1/LICENSE-APACHE rename to third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-MIT b/third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-MIT new file mode 100644 index 0000000..068d491 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-MIT @@ -0,0 +1,27 @@ +The MIT License (MIT) + +Copyright (c) 2019 The Crossbeam Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.2/LICENSE-THIRD-PARTY b/third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-THIRD-PARTY similarity index 100% rename from third_party/cargo/vendor/crossbeam-queue-0.2.2/LICENSE-THIRD-PARTY rename to third_party/cargo/vendor/crossbeam-queue-0.2.3/LICENSE-THIRD-PARTY diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/README.md b/third_party/cargo/vendor/crossbeam-queue-0.2.3/README.md new file mode 100644 index 0000000..646f9cf --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/README.md @@ -0,0 +1,67 @@ +# Crossbeam Queue + +[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)]( +https://travis-ci.org/crossbeam-rs/crossbeam) +[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam-queue/tree/master/src) +[![Cargo](https://img.shields.io/crates/v/crossbeam-queue.svg)]( +https://crates.io/crates/crossbeam-queue) +[![Documentation](https://docs.rs/crossbeam-queue/badge.svg)]( +https://docs.rs/crossbeam-queue) +[![Rust 1.28+](https://img.shields.io/badge/rust-1.28+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides concurrent queues that can be shared among threads: + +* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. +* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. + +[`ArrayQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.ArrayQueue.html +[`SegQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.SegQueue.html + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-queue = "0.2" +``` + +Next, add this to your crate: + +```rust +extern crate crossbeam_queue; +``` + +## Compatibility + +The minimum supported Rust version is 1.28. Any change to this is considered a breaking change. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +#### Third party software + +This product includes copies and modifications of software developed by third parties: + +* [src/array_queue.rs](src/array_queue.rs) is based on + [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) + by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. + +See the source code files for more details. + +Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/array_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/array_queue.rs new file mode 100644 index 0000000..45b055a --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/array_queue.rs @@ -0,0 +1,440 @@ +//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. +//! +//! Source: +//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue +//! +//! Copyright & License: +//! - Copyright (c) 2010-2011 Dmitry Vyukov +//! - Simplified BSD License and Apache License, Version 2.0 +//! - http://www.1024cores.net/home/code-license + +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use core::fmt; +use core::marker::PhantomData; +use core::mem; +use core::ptr; +use core::sync::atomic::{self, AtomicUsize, Ordering}; + +use crossbeam_utils::{Backoff, CachePadded}; + +use maybe_uninit::MaybeUninit; + +use err::{PopError, PushError}; + +/// A slot in a queue. +struct Slot { + /// The current stamp. + /// + /// If the stamp equals the tail, this node will be next written to. If it equals head + 1, + /// this node will be next read from. + stamp: AtomicUsize, + + /// The value in this slot. + value: UnsafeCell>, +} + +/// A bounded multi-producer multi-consumer queue. +/// +/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed +/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an +/// element into a full queue will fail. Having a buffer allocated upfront makes this queue a bit +/// faster than [`SegQueue`]. +/// +/// [`SegQueue`]: struct.SegQueue.html +/// +/// # Examples +/// +/// ``` +/// use crossbeam_queue::{ArrayQueue, PushError}; +/// +/// let q = ArrayQueue::new(2); +/// +/// assert_eq!(q.push('a'), Ok(())); +/// assert_eq!(q.push('b'), Ok(())); +/// assert_eq!(q.push('c'), Err(PushError('c'))); +/// assert_eq!(q.pop(), Ok('a')); +/// ``` +pub struct ArrayQueue { + /// The head of the queue. + /// + /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a + /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. + /// + /// Elements are popped from the head of the queue. + head: CachePadded, + + /// The tail of the queue. + /// + /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a + /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. + /// + /// Elements are pushed into the tail of the queue. + tail: CachePadded, + + /// The buffer holding slots. + buffer: *mut Slot, + + /// The queue capacity. + cap: usize, + + /// A stamp with the value of `{ lap: 1, index: 0 }`. + one_lap: usize, + + /// Indicates that dropping an `ArrayQueue` may drop elements of type `T`. + _marker: PhantomData, +} + +unsafe impl Sync for ArrayQueue {} +unsafe impl Send for ArrayQueue {} + +impl ArrayQueue { + /// Creates a new bounded queue with the given capacity. + /// + /// # Panics + /// + /// Panics if the capacity is zero. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::ArrayQueue; + /// + /// let q = ArrayQueue::::new(100); + /// ``` + pub fn new(cap: usize) -> ArrayQueue { + assert!(cap > 0, "capacity must be non-zero"); + + // Head is initialized to `{ lap: 0, index: 0 }`. + // Tail is initialized to `{ lap: 0, index: 0 }`. + let head = 0; + let tail = 0; + + // Allocate a buffer of `cap` slots. + let buffer = { + let mut v = Vec::>::with_capacity(cap); + let ptr = v.as_mut_ptr(); + mem::forget(v); + ptr + }; + + // Initialize stamps in the slots. + for i in 0..cap { + unsafe { + // Set the stamp to `{ lap: 0, index: i }`. + let slot = buffer.add(i); + ptr::write(&mut (*slot).stamp, AtomicUsize::new(i)); + } + } + + // One lap is the smallest power of two greater than `cap`. + let one_lap = (cap + 1).next_power_of_two(); + + ArrayQueue { + buffer, + cap, + one_lap, + head: CachePadded::new(AtomicUsize::new(head)), + tail: CachePadded::new(AtomicUsize::new(tail)), + _marker: PhantomData, + } + } + + /// Attempts to push an element into the queue. + /// + /// If the queue is full, the element is returned back as an error. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{ArrayQueue, PushError}; + /// + /// let q = ArrayQueue::new(1); + /// + /// assert_eq!(q.push(10), Ok(())); + /// assert_eq!(q.push(20), Err(PushError(20))); + /// ``` + pub fn push(&self, value: T) -> Result<(), PushError> { + let backoff = Backoff::new(); + let mut tail = self.tail.load(Ordering::Relaxed); + + loop { + // Deconstruct the tail. + let index = tail & (self.one_lap - 1); + let lap = tail & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the tail and the stamp match, we may attempt to push. + if tail == stamp { + let new_tail = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, index: index + 1 }`. + tail + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the tail. + match self.tail.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Write the value into the slot and update the stamp. + unsafe { + slot.value.get().write(MaybeUninit::new(value)); + } + slot.stamp.store(tail + 1, Ordering::Release); + return Ok(()); + } + Err(t) => { + tail = t; + backoff.spin(); + } + } + } else if stamp.wrapping_add(self.one_lap) == tail + 1 { + atomic::fence(Ordering::SeqCst); + let head = self.head.load(Ordering::Relaxed); + + // If the head lags one lap behind the tail as well... + if head.wrapping_add(self.one_lap) == tail { + // ...then the queue is full. + return Err(PushError(value)); + } + + backoff.spin(); + tail = self.tail.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + tail = self.tail.load(Ordering::Relaxed); + } + } + } + + /// Attempts to pop an element from the queue. + /// + /// If the queue is empty, an error is returned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{ArrayQueue, PopError}; + /// + /// let q = ArrayQueue::new(1); + /// assert_eq!(q.push(10), Ok(())); + /// + /// assert_eq!(q.pop(), Ok(10)); + /// assert_eq!(q.pop(), Err(PopError)); + /// ``` + pub fn pop(&self) -> Result { + let backoff = Backoff::new(); + let mut head = self.head.load(Ordering::Relaxed); + + loop { + // Deconstruct the head. + let index = head & (self.one_lap - 1); + let lap = head & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the the stamp is ahead of the head by 1, we may attempt to pop. + if head + 1 == stamp { + let new = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, index: index + 1 }`. + head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the head. + match self.head.compare_exchange_weak( + head, + new, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Read the value from the slot and update the stamp. + let msg = unsafe { slot.value.get().read().assume_init() }; + slot.stamp + .store(head.wrapping_add(self.one_lap), Ordering::Release); + return Ok(msg); + } + Err(h) => { + head = h; + backoff.spin(); + } + } + } else if stamp == head { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.load(Ordering::Relaxed); + + // If the tail equals the head, that means the channel is empty. + if tail == head { + return Err(PopError); + } + + backoff.spin(); + head = self.head.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + head = self.head.load(Ordering::Relaxed); + } + } + } + + /// Returns the capacity of the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{ArrayQueue, PopError}; + /// + /// let q = ArrayQueue::::new(100); + /// + /// assert_eq!(q.capacity(), 100); + /// ``` + pub fn capacity(&self) -> usize { + self.cap + } + + /// Returns `true` if the queue is empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{ArrayQueue, PopError}; + /// + /// let q = ArrayQueue::new(100); + /// + /// assert!(q.is_empty()); + /// q.push(1).unwrap(); + /// assert!(!q.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + let head = self.head.load(Ordering::SeqCst); + let tail = self.tail.load(Ordering::SeqCst); + + // Is the tail lagging one lap behind head? + // Is the tail equal to the head? + // + // Note: If the head changes just before we load the tail, that means there was a moment + // when the channel was not empty, so it is safe to just return `false`. + tail == head + } + + /// Returns `true` if the queue is full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{ArrayQueue, PopError}; + /// + /// let q = ArrayQueue::new(1); + /// + /// assert!(!q.is_full()); + /// q.push(1).unwrap(); + /// assert!(q.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // Is the head lagging one lap behind tail? + // + // Note: If the tail changes just before we load the head, that means there was a moment + // when the queue was not full, so it is safe to just return `false`. + head.wrapping_add(self.one_lap) == tail + } + + /// Returns the number of elements in the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{ArrayQueue, PopError}; + /// + /// let q = ArrayQueue::new(100); + /// assert_eq!(q.len(), 0); + /// + /// q.push(10).unwrap(); + /// assert_eq!(q.len(), 1); + /// + /// q.push(20).unwrap(); + /// assert_eq!(q.len(), 2); + /// ``` + pub fn len(&self) -> usize { + loop { + // Load the tail, then load the head. + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // If the tail didn't change, we've got consistent values to work with. + if self.tail.load(Ordering::SeqCst) == tail { + let hix = head & (self.one_lap - 1); + let tix = tail & (self.one_lap - 1); + + return if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if tail == head { + 0 + } else { + self.cap + }; + } + } + } +} + +impl Drop for ArrayQueue { + fn drop(&mut self) { + // Get the index of the head. + let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1); + + // Loop over all slots that hold a message and drop them. + for i in 0..self.len() { + // Compute the index of the next slot holding a message. + let index = if hix + i < self.cap { + hix + i + } else { + hix + i - self.cap + }; + + unsafe { + let p = { + let slot = &mut *self.buffer.add(index); + let value = &mut *slot.value.get(); + value.as_mut_ptr() + }; + p.drop_in_place(); + } + } + + // Finally, deallocate the buffer, but don't run any destructors. + unsafe { + Vec::from_raw_parts(self.buffer, 0, self.cap); + } + } +} + +impl fmt::Debug for ArrayQueue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ArrayQueue { .. }") + } +} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/err.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/err.rs new file mode 100644 index 0000000..42880e8 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/err.rs @@ -0,0 +1,47 @@ +use core::fmt; + +/// Error which occurs when popping from an empty queue. +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct PopError; + +impl fmt::Debug for PopError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "PopError".fmt(f) + } +} + +impl fmt::Display for PopError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "popping from an empty queue".fmt(f) + } +} + +#[cfg(features = "std")] +impl std::error::Error for PopError { + fn description(&self) -> &str { + "popping from an empty queue" + } +} + +/// Error which occurs when pushing into a full queue. +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct PushError(pub T); + +impl fmt::Debug for PushError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "PushError(..)".fmt(f) + } +} + +impl fmt::Display for PushError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "pushing into a full queue".fmt(f) + } +} + +#[cfg(features = "std")] +impl std::error::Error for PushError { + fn description(&self) -> &str { + "pushing into a full queue" + } +} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/lib.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/lib.rs new file mode 100644 index 0000000..fd99392 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/lib.rs @@ -0,0 +1,42 @@ +//! Concurrent queues. +//! +//! This crate provides concurrent queues that can be shared among threads: +//! +//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. +//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. +//! +//! [`ArrayQueue`]: struct.ArrayQueue.html +//! [`SegQueue`]: struct.SegQueue.html + +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[macro_use] +extern crate cfg_if; +#[cfg(feature = "std")] +extern crate core; + +extern crate maybe_uninit; + +cfg_if! { + if #[cfg(feature = "alloc")] { + extern crate alloc; + } else if #[cfg(feature = "std")] { + extern crate std as alloc; + } +} + +extern crate crossbeam_utils; + +cfg_if! { + if #[cfg(any(feature = "alloc", feature = "std"))] { + mod array_queue; + mod err; + mod seg_queue; + + pub use self::array_queue::ArrayQueue; + pub use self::err::{PopError, PushError}; + pub use self::seg_queue::SegQueue; + } +} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/seg_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/seg_queue.rs new file mode 100644 index 0000000..b52da4f --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/src/seg_queue.rs @@ -0,0 +1,490 @@ +use alloc::boxed::Box; +use core::cell::UnsafeCell; +use core::fmt; +use core::marker::PhantomData; +use core::ptr; +use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; + +use crossbeam_utils::{Backoff, CachePadded}; + +use maybe_uninit::MaybeUninit; + +use err::PopError; + +// Bits indicating the state of a slot: +// * If a value has been written into the slot, `WRITE` is set. +// * If a value has been read from the slot, `READ` is set. +// * If the block is being destroyed, `DESTROY` is set. +const WRITE: usize = 1; +const READ: usize = 2; +const DESTROY: usize = 4; + +// Each block covers one "lap" of indices. +const LAP: usize = 32; +// The maximum number of values a block can hold. +const BLOCK_CAP: usize = LAP - 1; +// How many lower bits are reserved for metadata. +const SHIFT: usize = 1; +// Indicates that the block is not the last one. +const HAS_NEXT: usize = 1; + +/// A slot in a block. +struct Slot { + /// The value. + value: UnsafeCell>, + + /// The state of the slot. + state: AtomicUsize, +} + +impl Slot { + /// Waits until a value is written into the slot. + fn wait_write(&self) { + let backoff = Backoff::new(); + while self.state.load(Ordering::Acquire) & WRITE == 0 { + backoff.snooze(); + } + } +} + +/// A block in a linked list. +/// +/// Each block in the list can hold up to `BLOCK_CAP` values. +struct Block { + /// The next block in the linked list. + next: AtomicPtr>, + + /// Slots for values. + slots: [Slot; BLOCK_CAP], +} + +impl Block { + /// Creates an empty block that starts at `start_index`. + fn new() -> Block { + // SAFETY: This is safe because: + // [1] `Block::next` (AtomicPtr) may be safely zero initialized. + // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. + // [3] `Slot::value` (UnsafeCell) may be safely zero initialized because it + // holds a MaybeUninit. + // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. + unsafe { MaybeUninit::zeroed().assume_init() } + } + + /// Waits until the next pointer is set. + fn wait_next(&self) -> *mut Block { + let backoff = Backoff::new(); + loop { + let next = self.next.load(Ordering::Acquire); + if !next.is_null() { + return next; + } + backoff.snooze(); + } + } + + /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. + unsafe fn destroy(this: *mut Block, start: usize) { + // It is not necessary to set the `DESTROY` bit in the last slot because that slot has + // begun destruction of the block. + for i in start..BLOCK_CAP - 1 { + let slot = (*this).slots.get_unchecked(i); + + // Mark the `DESTROY` bit if a thread is still using the slot. + if slot.state.load(Ordering::Acquire) & READ == 0 + && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 + { + // If a thread is still using the slot, it will continue destruction of the block. + return; + } + } + + // No thread is using the block, now it is safe to destroy it. + drop(Box::from_raw(this)); + } +} + +/// A position in a queue. +struct Position { + /// The index in the queue. + index: AtomicUsize, + + /// The block in the linked list. + block: AtomicPtr>, +} + +/// An unbounded multi-producer multi-consumer queue. +/// +/// This queue is implemented as a linked list of segments, where each segment is a small buffer +/// that can hold a handful of elements. There is no limit to how many elements can be in the queue +/// at a time. However, since segments need to be dynamically allocated as elements get pushed, +/// this queue is somewhat slower than [`ArrayQueue`]. +/// +/// [`ArrayQueue`]: struct.ArrayQueue.html +/// +/// # Examples +/// +/// ``` +/// use crossbeam_queue::{PopError, SegQueue}; +/// +/// let q = SegQueue::new(); +/// +/// q.push('a'); +/// q.push('b'); +/// +/// assert_eq!(q.pop(), Ok('a')); +/// assert_eq!(q.pop(), Ok('b')); +/// assert_eq!(q.pop(), Err(PopError)); +/// ``` +pub struct SegQueue { + /// The head of the queue. + head: CachePadded>, + + /// The tail of the queue. + tail: CachePadded>, + + /// Indicates that dropping a `SegQueue` may drop values of type `T`. + _marker: PhantomData, +} + +unsafe impl Send for SegQueue {} +unsafe impl Sync for SegQueue {} + +impl SegQueue { + /// Creates a new unbounded queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::SegQueue; + /// + /// let q = SegQueue::::new(); + /// ``` + pub fn new() -> SegQueue { + SegQueue { + head: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + tail: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + _marker: PhantomData, + } + } + + /// Pushes an element into the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::SegQueue; + /// + /// let q = SegQueue::new(); + /// + /// q.push(10); + /// q.push(20); + /// ``` + pub fn push(&self, value: T) { + let backoff = Backoff::new(); + let mut tail = self.tail.index.load(Ordering::Acquire); + let mut block = self.tail.block.load(Ordering::Acquire); + let mut next_block = None; + + loop { + // Calculate the offset of the index into the block. + let offset = (tail >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + + // If we're going to have to install the next block, allocate it in advance in order to + // make the wait for other threads as short as possible. + if offset + 1 == BLOCK_CAP && next_block.is_none() { + next_block = Some(Box::new(Block::::new())); + } + + // If this is the first push operation, we need to allocate the first block. + if block.is_null() { + let new = Box::into_raw(Box::new(Block::::new())); + + if self + .tail + .block + .compare_and_swap(block, new, Ordering::Release) + == block + { + self.head.block.store(new, Ordering::Release); + block = new; + } else { + next_block = unsafe { Some(Box::from_raw(new)) }; + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + } + + let new_tail = tail + (1 << SHIFT); + + // Try advancing the tail forward. + match self.tail.index.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, install the next one. + if offset + 1 == BLOCK_CAP { + let next_block = Box::into_raw(next_block.unwrap()); + let next_index = new_tail.wrapping_add(1 << SHIFT); + + self.tail.block.store(next_block, Ordering::Release); + self.tail.index.store(next_index, Ordering::Release); + (*block).next.store(next_block, Ordering::Release); + } + + // Write the value into the slot. + let slot = (*block).slots.get_unchecked(offset); + slot.value.get().write(MaybeUninit::new(value)); + slot.state.fetch_or(WRITE, Ordering::Release); + + return; + }, + Err(t) => { + tail = t; + block = self.tail.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Pops an element from the queue. + /// + /// If the queue is empty, an error is returned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{PopError, SegQueue}; + /// + /// let q = SegQueue::new(); + /// + /// q.push(10); + /// assert_eq!(q.pop(), Ok(10)); + /// assert_eq!(q.pop(), Err(PopError)); + /// ``` + pub fn pop(&self) -> Result { + let backoff = Backoff::new(); + let mut head = self.head.index.load(Ordering::Acquire); + let mut block = self.head.block.load(Ordering::Acquire); + + loop { + // Calculate the offset of the index into the block. + let offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + let mut new_head = head + (1 << SHIFT); + + if new_head & HAS_NEXT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the queue is empty. + if head >> SHIFT == tail >> SHIFT { + return Err(PopError); + } + + // If head and tail are not in the same block, set `HAS_NEXT` in head. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= HAS_NEXT; + } + } + + // The block can be null here only if the first push operation is in progress. In that + // case, just wait until it gets initialized. + if block.is_null() { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + // Try moving the head index forward. + match self.head.index.compare_exchange_weak( + head, + new_head, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, move to the next one. + if offset + 1 == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= HAS_NEXT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + // Read the value. + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let value = slot.value.get().read().assume_init(); + + // Destroy the block if we've reached the end, or if another thread wanted to + // destroy but couldn't because we were busy reading from the slot. + if offset + 1 == BLOCK_CAP { + Block::destroy(block, 0); + } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset + 1); + } + + return Ok(value); + }, + Err(h) => { + head = h; + block = self.head.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Returns `true` if the queue is empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::SegQueue; + /// + /// let q = SegQueue::new(); + /// + /// assert!(q.is_empty()); + /// q.push(1); + /// assert!(!q.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + let head = self.head.index.load(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::SeqCst); + head >> SHIFT == tail >> SHIFT + } + + /// Returns the number of elements in the queue. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_queue::{SegQueue, PopError}; + /// + /// let q = SegQueue::new(); + /// assert_eq!(q.len(), 0); + /// + /// q.push(10); + /// assert_eq!(q.len(), 1); + /// + /// q.push(20); + /// assert_eq!(q.len(), 2); + /// ``` + pub fn len(&self) -> usize { + loop { + // Load the tail index, then load the head index. + let mut tail = self.tail.index.load(Ordering::SeqCst); + let mut head = self.head.index.load(Ordering::SeqCst); + + // If the tail index didn't change, we've got consistent indices to work with. + if self.tail.index.load(Ordering::SeqCst) == tail { + // Erase the lower bits. + tail &= !((1 << SHIFT) - 1); + head &= !((1 << SHIFT) - 1); + + // Rotate indices so that head falls into the first block. + let lap = (head >> SHIFT) / LAP; + tail = tail.wrapping_sub((lap * LAP) << SHIFT); + head = head.wrapping_sub((lap * LAP) << SHIFT); + + // Remove the lower bits. + tail >>= SHIFT; + head >>= SHIFT; + + // Fix up indices if they fall onto block ends. + if head == BLOCK_CAP { + head = 0; + tail -= LAP; + } + if tail == BLOCK_CAP { + tail += 1; + } + + // Return the difference minus the number of blocks between tail and head. + return tail - head - tail / LAP; + } + } + } +} + +impl Drop for SegQueue { + fn drop(&mut self) { + let mut head = self.head.index.load(Ordering::Relaxed); + let mut tail = self.tail.index.load(Ordering::Relaxed); + let mut block = self.head.block.load(Ordering::Relaxed); + + // Erase the lower bits. + head &= !((1 << SHIFT) - 1); + tail &= !((1 << SHIFT) - 1); + + unsafe { + // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. + while head != tail { + let offset = (head >> SHIFT) % LAP; + + if offset < BLOCK_CAP { + // Drop the value in the slot. + let slot = (*block).slots.get_unchecked(offset); + let p = &mut *slot.value.get(); + p.as_mut_ptr().drop_in_place(); + } else { + // Deallocate the block and move to the next one. + let next = (*block).next.load(Ordering::Relaxed); + drop(Box::from_raw(block)); + block = next; + } + + head = head.wrapping_add(1 << SHIFT); + } + + // Deallocate the last remaining block. + if !block.is_null() { + drop(Box::from_raw(block)); + } + } + } +} + +impl fmt::Debug for SegQueue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("SegQueue { .. }") + } +} + +impl Default for SegQueue { + fn default() -> SegQueue { + SegQueue::new() + } +} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/tests/array_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.3/tests/array_queue.rs new file mode 100644 index 0000000..a4f64f3 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/tests/array_queue.rs @@ -0,0 +1,254 @@ +extern crate crossbeam_queue; +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::atomic::{AtomicUsize, Ordering}; + +use crossbeam_queue::ArrayQueue; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +#[test] +fn smoke() { + let q = ArrayQueue::new(1); + + q.push(7).unwrap(); + assert_eq!(q.pop(), Ok(7)); + + q.push(8).unwrap(); + assert_eq!(q.pop(), Ok(8)); + assert!(q.pop().is_err()); +} + +#[test] +fn capacity() { + for i in 1..10 { + let q = ArrayQueue::::new(i); + assert_eq!(q.capacity(), i); + } +} + +#[test] +#[should_panic(expected = "capacity must be non-zero")] +fn zero_capacity() { + let _ = ArrayQueue::::new(0); +} + +#[test] +fn len_empty_full() { + let q = ArrayQueue::new(2); + + assert_eq!(q.len(), 0); + assert_eq!(q.is_empty(), true); + assert_eq!(q.is_full(), false); + + q.push(()).unwrap(); + + assert_eq!(q.len(), 1); + assert_eq!(q.is_empty(), false); + assert_eq!(q.is_full(), false); + + q.push(()).unwrap(); + + assert_eq!(q.len(), 2); + assert_eq!(q.is_empty(), false); + assert_eq!(q.is_full(), true); + + q.pop().unwrap(); + + assert_eq!(q.len(), 1); + assert_eq!(q.is_empty(), false); + assert_eq!(q.is_full(), false); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + const CAP: usize = 1000; + + let q = ArrayQueue::new(CAP); + assert_eq!(q.len(), 0); + + for _ in 0..CAP / 10 { + for i in 0..50 { + q.push(i).unwrap(); + assert_eq!(q.len(), i + 1); + } + + for i in 0..50 { + q.pop().unwrap(); + assert_eq!(q.len(), 50 - i - 1); + } + } + assert_eq!(q.len(), 0); + + for i in 0..CAP { + q.push(i).unwrap(); + assert_eq!(q.len(), i + 1); + } + + for _ in 0..CAP { + q.pop().unwrap(); + } + assert_eq!(q.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + loop { + if let Ok(x) = q.pop() { + assert_eq!(x, i); + break; + } + } + let len = q.len(); + assert!(len <= CAP); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + while q.push(i).is_err() {} + let len = q.len(); + assert!(len <= CAP); + } + }); + }) + .unwrap(); + assert_eq!(q.len(), 0); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let q = ArrayQueue::new(3); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + loop { + if let Ok(x) = q.pop() { + assert_eq!(x, i); + break; + } + } + } + assert!(q.pop().is_err()); + }); + + scope.spawn(|_| { + for i in 0..COUNT { + while q.push(i).is_err() {} + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let q = ArrayQueue::::new(3); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = loop { + if let Ok(x) = q.pop() { + break x; + } + }; + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + while q.push(i).is_err() {} + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn drops() { + const RUNS: usize = 100; + + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..RUNS { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 50); + + DROPS.store(0, Ordering::SeqCst); + let q = ArrayQueue::new(50); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + while q.pop().is_err() {} + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + while q.push(DropCounter).is_err() { + DROPS.fetch_sub(1, Ordering::SeqCst); + } + } + }); + }) + .unwrap(); + + for _ in 0..additional { + q.push(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(q); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let q = ArrayQueue::new(THREADS); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + while q.push(0).is_err() {} + q.pop().unwrap(); + } + }); + } + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-queue-0.2.3/tests/seg_queue.rs b/third_party/cargo/vendor/crossbeam-queue-0.2.3/tests/seg_queue.rs new file mode 100644 index 0000000..ec32e1f --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-queue-0.2.3/tests/seg_queue.rs @@ -0,0 +1,167 @@ +extern crate crossbeam_queue; +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::atomic::{AtomicUsize, Ordering}; + +use crossbeam_queue::SegQueue; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +#[test] +fn smoke() { + let q = SegQueue::new(); + q.push(7); + assert_eq!(q.pop(), Ok(7)); + + q.push(8); + assert_eq!(q.pop(), Ok(8)); + assert!(q.pop().is_err()); +} + +#[test] +fn len_empty_full() { + let q = SegQueue::new(); + + assert_eq!(q.len(), 0); + assert_eq!(q.is_empty(), true); + + q.push(()); + + assert_eq!(q.len(), 1); + assert_eq!(q.is_empty(), false); + + q.pop().unwrap(); + + assert_eq!(q.len(), 0); + assert_eq!(q.is_empty(), true); +} + +#[test] +fn len() { + let q = SegQueue::new(); + + assert_eq!(q.len(), 0); + + for i in 0..50 { + q.push(i); + assert_eq!(q.len(), i + 1); + } + + for i in 0..50 { + q.pop().unwrap(); + assert_eq!(q.len(), 50 - i - 1); + } + + assert_eq!(q.len(), 0); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let q = SegQueue::new(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + loop { + if let Ok(x) = q.pop() { + assert_eq!(x, i); + break; + } + } + } + assert!(q.pop().is_err()); + }); + scope.spawn(|_| { + for i in 0..COUNT { + q.push(i); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let q = SegQueue::::new(); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = loop { + if let Ok(x) = q.pop() { + break x; + } + }; + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + q.push(i); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn drops() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..100 { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 1000); + + DROPS.store(0, Ordering::SeqCst); + let q = SegQueue::new(); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + while q.pop().is_err() {} + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + q.push(DropCounter); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + q.push(DropCounter); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(q); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/.cargo-checksum.json b/third_party/cargo/vendor/crossbeam-utils-0.8.1/.cargo-checksum.json new file mode 100644 index 0000000..9a26461 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"36557d1a612004b5108ed46be3716bb2e06368d5bb0cd9e7ea4b6bcc4d81c07a","Cargo.toml":"648a34c3609f0cb729929fd5c6d1288475232a4daeb79363e629ecadcc5d3a4f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"5bbcf23ea854d44870790a316dbcdb8d7b0c2e0f17a521e8d4fbffdd9dd5b464","benches/atomic_cell.rs":"de327015cf811fb74b7a624719f678ba0677025dc703d56cbd2094a3c92da23b","build.rs":"f927f9796b0cbae832f458e82833b24c7ced9f27f4f1e76de9d11ad30d21c88a","src/atomic/atomic_cell.rs":"4b86367084da93176c335650524220ef7b3df4df09b6535d0b55a03446dee7e0","src/atomic/consume.rs":"1ee5de160b6e3755c02940c24fa90f85f3ef2f7afb971e9e9c6f481609bbc7b7","src/atomic/mod.rs":"c84d068944388c1385d6fec9211b6be26c777a21fc04e7231d1f3b564de62708","src/atomic/seq_lock.rs":"ee50097cd582cfe6e28ebc54935fc6488f52e2fed19d4b26bafd5eab5c229291","src/atomic/seq_lock_wide.rs":"f03ee779c2ebebcfb0df8baac49be7d38e920876260c8da9dff0fc894068c35d","src/backoff.rs":"98d1daee75bbd6243bc0784c92c56086e57658baff93a2a1f0729426901c03ee","src/cache_padded.rs":"5671f3a02f6e407f1dc562d4fb17e4659f18d1e5206b8566b38d2e447e5f6fa4","src/lib.rs":"61c6bc2b43d87550c4547693f3eacfe126581560a8884b32b23f01a7e2c6d833","src/sync/mod.rs":"e5f4087c4e63b0e6e0b291f3946a224aa9d2a4a0c299c23014b822d6346f6986","src/sync/parker.rs":"6137fccce8c03045440cbc3166721e4e4b5f73013165c9c260cff904cfcab6f3","src/sync/sharded_lock.rs":"14be659744918d0b27db24c56b41c618b0f0484b6761da46561023d96c4c120f","src/sync/wait_group.rs":"932e11753764b238f764892978a6b70fb288111faf7fae7766e603bed4e5b444","src/thread.rs":"6c44bf4c4515a769b8ccd0c9d9b80f5b46bd4768ec323a909773301d375033fb","tests/atomic_cell.rs":"5efe71777d7687ee01e387d5ca20436c3e8171e1e879a63074d1f79ccc88ff5e","tests/cache_padded.rs":"6ba6ad1b3060bfb2f7bf0a1d006f949d91c49e506564b0d28e4f06129b94665d","tests/parker.rs":"a1f63cf99b3524bfc91d0797133d0b75165445ecbaa92f78bd8101fa7cc828ec","tests/sharded_lock.rs":"c7d9f7185900b3ff84d00f5252793d5d28c47374678b8e6f758a67fa32c71fca","tests/thread.rs":"9a7d7d3028c552fd834c68598b04a1cc252a816bc20ab62cec060d6cd09cab10","tests/wait_group.rs":"ad8f0cdfed31f9594a2e0737234d418f8b924d784a4db8d7e469deab8c95f5f8"},"package":"02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"} \ No newline at end of file diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/BUILD.bazel b/third_party/cargo/vendor/crossbeam-utils-0.8.1/BUILD.bazel new file mode 100644 index 0000000..9dadc62 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/BUILD.bazel @@ -0,0 +1,74 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +# Unsupported target "atomic_cell" with type "bench" omitted + +# Unsupported target "build-script-build" with type "custom-build" omitted + +rust_library( + name = "crossbeam_utils", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "lazy_static", + "std", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.8.1", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/cfg-if-1.0.0:cfg_if", + "//third_party/cargo/vendor/lazy_static-1.4.0:lazy_static", + ], +) + +# Unsupported target "atomic_cell" with type "test" omitted + +# Unsupported target "cache_padded" with type "test" omitted + +# Unsupported target "parker" with type "test" omitted + +# Unsupported target "sharded_lock" with type "test" omitted + +# Unsupported target "thread" with type "test" omitted + +# Unsupported target "wait_group" with type "test" omitted diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/CHANGELOG.md b/third_party/cargo/vendor/crossbeam-utils-0.8.1/CHANGELOG.md new file mode 100644 index 0000000..a17c6e6 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/CHANGELOG.md @@ -0,0 +1,129 @@ +# Version 0.8.1 + +- Make `AtomicCell::is_lock_free` always const fn. (#600) +- Fix a bug in `seq_lock_wide`. (#596) +- Remove `const_fn` dependency. (#600) +- `crossbeam-utils` no longer fails to compile if unable to determine rustc version. Instead, it now displays a warning. (#604) + +# Version 0.8.0 + +- Bump the minimum supported Rust version to 1.36. +- Remove deprecated `AtomicCell::get_mut()` and `Backoff::is_complete()` methods +- Remove `alloc` feature. +- Make `CachePadded::new()` const function. +- Make `AtomicCell::is_lock_free()` const function at 1.46+. +- Implement `From` for `AtomicCell`. + +# Version 0.7.2 + +- Fix bug in release (yanking 0.7.1) + +# Version 0.7.1 + +- Bump `autocfg` dependency to version 1.0. (#460) +- Make `AtomicCell` lockfree for u8, u16, u32, u64 sized values at 1.34+. (#454) + +# Version 0.7.0 + +- Bump the minimum required version to 1.28. +- Fix breakage with nightly feature due to rust-lang/rust#65214. +- Apply `#[repr(transparent)]` to `AtomicCell`. +- Make `AtomicCell::new()` const function at 1.31+. + +# Version 0.6.6 + +- Add `UnwindSafe` and `RefUnwindSafe` impls for `AtomicCell`. +- Add `AtomicCell::as_ptr()`. +- Add `AtomicCell::take()`. +- Fix a bug in `AtomicCell::compare_exchange()` and `AtomicCell::compare_and_swap()`. +- Various documentation improvements. + +# Version 0.6.5 + +- Rename `Backoff::is_complete()` to `Backoff::is_completed()`. + +# Version 0.6.4 + +- Add `WaitGroup`, `ShardedLock`, and `Backoff`. +- Add `fetch_*` methods for `AtomicCell` and `AtomicCell`. +- Expand documentation. + +# Version 0.6.3 + +- Add `AtomicCell`. +- Improve documentation. + +# Version 0.6.2 + +- Add `Parker`. +- Improve documentation. + +# Version 0.6.1 + +- Fix a soundness bug in `Scope::spawn()`. +- Remove the `T: 'scope` bound on `ScopedJoinHandle`. + +# Version 0.6.0 + +- Move `AtomicConsume` to `atomic` module. +- `scope()` returns a `Result` of thread joins. +- Remove `spawn_unchecked`. +- Fix a soundness bug due to incorrect lifetimes. +- Improve documentation. +- Support nested scoped spawns. +- Implement `Copy`, `Hash`, `PartialEq`, and `Eq` for `CachePadded`. +- Add `CachePadded::into_inner()`. + +# Version 0.5.0 + +- Reorganize sub-modules and rename functions. + +# Version 0.4.1 + +- Fix a documentation link. + +# Version 0.4.0 + +- `CachePadded` supports types bigger than 64 bytes. +- Fix a bug in scoped threads where unitialized memory was being dropped. +- Minimum required Rust version is now 1.25. + +# Version 0.3.2 + +- Mark `load_consume` with `#[inline]`. + +# Version 0.3.1 + +- `load_consume` on ARM and AArch64. + +# Version 0.3.0 + +- Add `join` for scoped thread API. +- Add `load_consume` for atomic load-consume memory ordering. +- Remove `AtomicOption`. + +# Version 0.2.2 + +- Support Rust 1.12.1. +- Call `T::clone` when cloning a `CachePadded`. + +# Version 0.2.1 + +- Add `use_std` feature. + +# Version 0.2.0 + +- Add `nightly` feature. +- Use `repr(align(64))` on `CachePadded` with the `nightly` feature. +- Implement `Drop` for `CachePadded`. +- Implement `Clone` for `CachePadded`. +- Implement `From` for `CachePadded`. +- Implement better `Debug` for `CachePadded`. +- Write more tests. +- Add this changelog. +- Change cache line length to 64 bytes. +- Remove `ZerosValid`. + +# Version 0.1.0 + +- Old implementation of `CachePadded` from `crossbeam` version 0.3.0 diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/Cargo.toml b/third_party/cargo/vendor/crossbeam-utils-0.8.1/Cargo.toml new file mode 100644 index 0000000..edb08f9 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "crossbeam-utils" +version = "0.8.1" +authors = ["The Crossbeam Project Developers"] +description = "Utilities for concurrent programming" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" +documentation = "https://docs.rs/crossbeam-utils" +readme = "README.md" +keywords = ["scoped", "thread", "atomic", "cache"] +categories = ["algorithms", "concurrency", "data-structures", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dependencies.cfg-if] +version = "1" + +[dependencies.lazy_static] +version = "1.4.0" +optional = true +[dev-dependencies.rand] +version = "0.7.3" +[build-dependencies.autocfg] +version = "1.0.0" + +[features] +default = ["std"] +nightly = [] +std = ["lazy_static"] diff --git a/third_party/cargo/vendor/either-1.5.3/LICENSE-APACHE b/third_party/cargo/vendor/crossbeam-utils-0.8.1/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/either-1.5.3/LICENSE-APACHE rename to third_party/cargo/vendor/crossbeam-utils-0.8.1/LICENSE-APACHE diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/LICENSE-MIT b/third_party/cargo/vendor/crossbeam-utils-0.8.1/LICENSE-MIT new file mode 100644 index 0000000..068d491 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/LICENSE-MIT @@ -0,0 +1,27 @@ +The MIT License (MIT) + +Copyright (c) 2019 The Crossbeam Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/README.md b/third_party/cargo/vendor/crossbeam-utils-0.8.1/README.md new file mode 100644 index 0000000..7e95829 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/README.md @@ -0,0 +1,73 @@ +# Crossbeam Utils + +[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( +https://github.com/crossbeam-rs/crossbeam/actions) +[![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils#license) +[![Cargo](https://img.shields.io/crates/v/crossbeam-utils.svg)]( +https://crates.io/crates/crossbeam-utils) +[![Documentation](https://docs.rs/crossbeam-utils/badge.svg)]( +https://docs.rs/crossbeam-utils) +[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides miscellaneous tools for concurrent programming: + +#### Atomics + +* [`AtomicCell`], a thread-safe mutable memory location.(no_std) +* [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering.(no_std) + +#### Thread synchronization + +* [`Parker`], a thread parking primitive. +* [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. +* [`WaitGroup`], for synchronizing the beginning or end of some computation. + +#### Utilities + +* [`Backoff`], for exponential backoff in spin loops.(no_std) +* [`CachePadded`], for padding and aligning a value to the length of a cache line.(no_std) +* [`scope`], for spawning threads that borrow local variables from the stack. + +*Features marked with (no_std) can be used in `no_std` environments.*
+ +[`AtomicCell`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/atomic/struct.AtomicCell.html +[`AtomicConsume`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/atomic/trait.AtomicConsume.html +[`Parker`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/sync/struct.Parker.html +[`ShardedLock`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/sync/struct.ShardedLock.html +[`WaitGroup`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/sync/struct.WaitGroup.html +[`Backoff`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/struct.Backoff.html +[`CachePadded`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/struct.CachePadded.html +[`scope`]: https://docs.rs/crossbeam-utils/*/crossbeam_utils/thread/fn.scope.html + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-utils = "0.8" +``` + +## Compatibility + +Crossbeam Utils supports stable Rust releases going back at least six months, +and every time the minimum supported Rust version is increased, a new minor +version is released. Currently, the minimum supported Rust version is 1.36. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/benches/atomic_cell.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/benches/atomic_cell.rs new file mode 100644 index 0000000..938a8fe --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/benches/atomic_cell.rs @@ -0,0 +1,156 @@ +#![feature(test)] + +extern crate test; + +use std::sync::Barrier; + +use crossbeam_utils::atomic::AtomicCell; +use crossbeam_utils::thread; + +#[bench] +fn load_u8(b: &mut test::Bencher) { + let a = AtomicCell::new(0u8); + let mut sum = 0; + b.iter(|| sum += a.load()); + test::black_box(sum); +} + +#[bench] +fn store_u8(b: &mut test::Bencher) { + let a = AtomicCell::new(0u8); + b.iter(|| a.store(1)); +} + +#[bench] +fn fetch_add_u8(b: &mut test::Bencher) { + let a = AtomicCell::new(0u8); + b.iter(|| a.fetch_add(1)); +} + +#[bench] +fn compare_and_swap_u8(b: &mut test::Bencher) { + let a = AtomicCell::new(0u8); + let mut i = 0; + b.iter(|| { + a.compare_and_swap(i, i.wrapping_add(1)); + i = i.wrapping_add(1); + }); +} + +#[bench] +fn concurrent_load_u8(b: &mut test::Bencher) { + const THREADS: usize = 2; + const STEPS: usize = 1_000_000; + + let start = Barrier::new(THREADS + 1); + let end = Barrier::new(THREADS + 1); + let exit = AtomicCell::new(false); + + let a = AtomicCell::new(0u8); + + thread::scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| loop { + start.wait(); + + let mut sum = 0; + for _ in 0..STEPS { + sum += a.load(); + } + test::black_box(sum); + + end.wait(); + if exit.load() { + break; + } + }); + } + + start.wait(); + end.wait(); + + b.iter(|| { + start.wait(); + end.wait(); + }); + + start.wait(); + exit.store(true); + end.wait(); + }) + .unwrap(); +} + +#[bench] +fn load_usize(b: &mut test::Bencher) { + let a = AtomicCell::new(0usize); + let mut sum = 0; + b.iter(|| sum += a.load()); + test::black_box(sum); +} + +#[bench] +fn store_usize(b: &mut test::Bencher) { + let a = AtomicCell::new(0usize); + b.iter(|| a.store(1)); +} + +#[bench] +fn fetch_add_usize(b: &mut test::Bencher) { + let a = AtomicCell::new(0usize); + b.iter(|| a.fetch_add(1)); +} + +#[bench] +fn compare_and_swap_usize(b: &mut test::Bencher) { + let a = AtomicCell::new(0usize); + let mut i = 0; + b.iter(|| { + a.compare_and_swap(i, i.wrapping_add(1)); + i = i.wrapping_add(1); + }); +} + +#[bench] +fn concurrent_load_usize(b: &mut test::Bencher) { + const THREADS: usize = 2; + const STEPS: usize = 1_000_000; + + let start = Barrier::new(THREADS + 1); + let end = Barrier::new(THREADS + 1); + let exit = AtomicCell::new(false); + + let a = AtomicCell::new(0usize); + + thread::scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| loop { + start.wait(); + + let mut sum = 0; + for _ in 0..STEPS { + sum += a.load(); + } + test::black_box(sum); + + end.wait(); + if exit.load() { + break; + } + }); + } + + start.wait(); + end.wait(); + + b.iter(|| { + start.wait(); + end.wait(); + }); + + start.wait(); + exit.store(true); + end.wait(); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/build.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/build.rs new file mode 100644 index 0000000..3e51021 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/build.rs @@ -0,0 +1,23 @@ +use autocfg::AutoCfg; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let cfg = match AutoCfg::new() { + Ok(cfg) => cfg, + Err(e) => { + println!( + "cargo:warning=crossbeam-utils: unable to determine rustc version: {}", + e + ); + return; + } + }; + + cfg.emit_type_cfg("core::sync::atomic::AtomicU8", "has_atomic_u8"); + cfg.emit_type_cfg("core::sync::atomic::AtomicU16", "has_atomic_u16"); + cfg.emit_type_cfg("core::sync::atomic::AtomicU32", "has_atomic_u32"); + cfg.emit_type_cfg("core::sync::atomic::AtomicU64", "has_atomic_u64"); + cfg.emit_type_cfg("core::sync::atomic::AtomicU128", "has_atomic_u128"); +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/atomic_cell.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/atomic_cell.rs new file mode 100644 index 0000000..e8f6804 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/atomic_cell.rs @@ -0,0 +1,971 @@ +// Necessary for implementing atomic methods for `AtomicUnit` +#![allow(clippy::unit_arg)] +#![allow(clippy::let_unit_value)] + +use core::cell::UnsafeCell; +use core::fmt; +use core::mem; +use core::ptr; +use core::sync::atomic::{self, AtomicBool, Ordering}; + +#[cfg(feature = "std")] +use std::panic::{RefUnwindSafe, UnwindSafe}; + +use super::seq_lock::SeqLock; + +/// A thread-safe mutable memory location. +/// +/// This type is equivalent to [`Cell`], except it can also be shared among multiple threads. +/// +/// Operations on `AtomicCell`s use atomic instructions whenever possible, and synchronize using +/// global locks otherwise. You can call [`AtomicCell::::is_lock_free()`] to check whether +/// atomic instructions or locks will be used. +/// +/// Atomic loads use the [`Acquire`] ordering and atomic stores use the [`Release`] ordering. +/// +/// [`Cell`]: std::cell::Cell +/// [`AtomicCell::::is_lock_free()`]: AtomicCell::is_lock_free +/// [`Acquire`]: std::sync::atomic::Ordering::Acquire +/// [`Release`]: std::sync::atomic::Ordering::Release +#[repr(transparent)] +pub struct AtomicCell { + /// The inner value. + /// + /// If this value can be transmuted into a primitive atomic type, it will be treated as such. + /// Otherwise, all potentially concurrent operations on this data will be protected by a global + /// lock. + value: UnsafeCell, +} + +unsafe impl Send for AtomicCell {} +unsafe impl Sync for AtomicCell {} + +#[cfg(feature = "std")] +impl UnwindSafe for AtomicCell {} +#[cfg(feature = "std")] +impl RefUnwindSafe for AtomicCell {} + +impl AtomicCell { + /// Creates a new atomic cell initialized with `val`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(7); + /// ``` + pub const fn new(val: T) -> AtomicCell { + AtomicCell { + value: UnsafeCell::new(val), + } + } + + /// Consumes the atomic and returns the contained value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(7); + /// let v = a.into_inner(); + /// + /// assert_eq!(v, 7); + /// ``` + pub fn into_inner(self) -> T { + self.value.into_inner() + } + + /// Returns `true` if operations on values of this type are lock-free. + /// + /// If the compiler or the platform doesn't support the necessary atomic instructions, + /// `AtomicCell` will use global locks for every potentially concurrent atomic operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// // This type is internally represented as `AtomicUsize` so we can just use atomic + /// // operations provided by it. + /// assert_eq!(AtomicCell::::is_lock_free(), true); + /// + /// // A wrapper struct around `isize`. + /// struct Foo { + /// bar: isize, + /// } + /// // `AtomicCell` will be internally represented as `AtomicIsize`. + /// assert_eq!(AtomicCell::::is_lock_free(), true); + /// + /// // Operations on zero-sized types are always lock-free. + /// assert_eq!(AtomicCell::<()>::is_lock_free(), true); + /// + /// // Very large types cannot be represented as any of the standard atomic types, so atomic + /// // operations on them will have to use global locks for synchronization. + /// assert_eq!(AtomicCell::<[u8; 1000]>::is_lock_free(), false); + /// ``` + pub const fn is_lock_free() -> bool { + atomic_is_lock_free::() + } + + /// Stores `val` into the atomic cell. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(7); + /// + /// assert_eq!(a.load(), 7); + /// a.store(8); + /// assert_eq!(a.load(), 8); + /// ``` + pub fn store(&self, val: T) { + if mem::needs_drop::() { + drop(self.swap(val)); + } else { + unsafe { + atomic_store(self.value.get(), val); + } + } + } + + /// Stores `val` into the atomic cell and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(7); + /// + /// assert_eq!(a.load(), 7); + /// assert_eq!(a.swap(8), 7); + /// assert_eq!(a.load(), 8); + /// ``` + pub fn swap(&self, val: T) -> T { + unsafe { atomic_swap(self.value.get(), val) } + } +} + +impl AtomicCell { + /// Returns a raw pointer to the underlying data in this atomic cell. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(5); + /// + /// let ptr = a.as_ptr(); + /// ``` + #[inline] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } +} + +impl AtomicCell { + /// Takes the value of the atomic cell, leaving `Default::default()` in its place. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(5); + /// let five = a.take(); + /// + /// assert_eq!(five, 5); + /// assert_eq!(a.into_inner(), 0); + /// ``` + pub fn take(&self) -> T { + self.swap(Default::default()) + } +} + +impl AtomicCell { + /// Loads a value from the atomic cell. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(7); + /// + /// assert_eq!(a.load(), 7); + /// ``` + pub fn load(&self) -> T { + unsafe { atomic_load(self.value.get()) } + } +} + +impl AtomicCell { + /// If the current value equals `current`, stores `new` into the atomic cell. + /// + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(1); + /// + /// assert_eq!(a.compare_and_swap(2, 3), 1); + /// assert_eq!(a.load(), 1); + /// + /// assert_eq!(a.compare_and_swap(1, 2), 1); + /// assert_eq!(a.load(), 2); + /// ``` + pub fn compare_and_swap(&self, current: T, new: T) -> T { + match self.compare_exchange(current, new) { + Ok(v) => v, + Err(v) => v, + } + } + + /// If the current value equals `current`, stores `new` into the atomic cell. + /// + /// The return value is a result indicating whether the new value was written and containing + /// the previous value. On success this value is guaranteed to be equal to `current`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(1); + /// + /// assert_eq!(a.compare_exchange(2, 3), Err(1)); + /// assert_eq!(a.load(), 1); + /// + /// assert_eq!(a.compare_exchange(1, 2), Ok(1)); + /// assert_eq!(a.load(), 2); + /// ``` + pub fn compare_exchange(&self, current: T, new: T) -> Result { + unsafe { atomic_compare_exchange_weak(self.value.get(), current, new) } + } +} + +macro_rules! impl_arithmetic { + ($t:ty, $example:tt) => { + impl AtomicCell<$t> { + /// Increments the current value by `val` and returns the previous value. + /// + /// The addition wraps on overflow. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_add(3), 7); + /// assert_eq!(a.load(), 10); + /// ``` + #[inline] + pub fn fetch_add(&self, val: $t) -> $t { + if can_transmute::<$t, atomic::AtomicUsize>() { + let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) }; + a.fetch_add(val as usize, Ordering::AcqRel) as $t + } else { + let _guard = lock(self.value.get() as usize).write(); + let value = unsafe { &mut *(self.value.get()) }; + let old = *value; + *value = value.wrapping_add(val); + old + } + } + + /// Decrements the current value by `val` and returns the previous value. + /// + /// The subtraction wraps on overflow. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_sub(3), 7); + /// assert_eq!(a.load(), 4); + /// ``` + #[inline] + pub fn fetch_sub(&self, val: $t) -> $t { + if can_transmute::<$t, atomic::AtomicUsize>() { + let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) }; + a.fetch_sub(val as usize, Ordering::AcqRel) as $t + } else { + let _guard = lock(self.value.get() as usize).write(); + let value = unsafe { &mut *(self.value.get()) }; + let old = *value; + *value = value.wrapping_sub(val); + old + } + } + + /// Applies bitwise "and" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_and(3), 7); + /// assert_eq!(a.load(), 3); + /// ``` + #[inline] + pub fn fetch_and(&self, val: $t) -> $t { + if can_transmute::<$t, atomic::AtomicUsize>() { + let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) }; + a.fetch_and(val as usize, Ordering::AcqRel) as $t + } else { + let _guard = lock(self.value.get() as usize).write(); + let value = unsafe { &mut *(self.value.get()) }; + let old = *value; + *value &= val; + old + } + } + + /// Applies bitwise "or" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_or(16), 7); + /// assert_eq!(a.load(), 23); + /// ``` + #[inline] + pub fn fetch_or(&self, val: $t) -> $t { + if can_transmute::<$t, atomic::AtomicUsize>() { + let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) }; + a.fetch_or(val as usize, Ordering::AcqRel) as $t + } else { + let _guard = lock(self.value.get() as usize).write(); + let value = unsafe { &mut *(self.value.get()) }; + let old = *value; + *value |= val; + old + } + } + + /// Applies bitwise "xor" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_xor(2), 7); + /// assert_eq!(a.load(), 5); + /// ``` + #[inline] + pub fn fetch_xor(&self, val: $t) -> $t { + if can_transmute::<$t, atomic::AtomicUsize>() { + let a = unsafe { &*(self.value.get() as *const atomic::AtomicUsize) }; + a.fetch_xor(val as usize, Ordering::AcqRel) as $t + } else { + let _guard = lock(self.value.get() as usize).write(); + let value = unsafe { &mut *(self.value.get()) }; + let old = *value; + *value ^= val; + old + } + } + } + }; + ($t:ty, $atomic:ty, $example:tt) => { + impl AtomicCell<$t> { + /// Increments the current value by `val` and returns the previous value. + /// + /// The addition wraps on overflow. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_add(3), 7); + /// assert_eq!(a.load(), 10); + /// ``` + #[inline] + pub fn fetch_add(&self, val: $t) -> $t { + let a = unsafe { &*(self.value.get() as *const $atomic) }; + a.fetch_add(val, Ordering::AcqRel) + } + + /// Decrements the current value by `val` and returns the previous value. + /// + /// The subtraction wraps on overflow. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_sub(3), 7); + /// assert_eq!(a.load(), 4); + /// ``` + #[inline] + pub fn fetch_sub(&self, val: $t) -> $t { + let a = unsafe { &*(self.value.get() as *const $atomic) }; + a.fetch_sub(val, Ordering::AcqRel) + } + + /// Applies bitwise "and" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_and(3), 7); + /// assert_eq!(a.load(), 3); + /// ``` + #[inline] + pub fn fetch_and(&self, val: $t) -> $t { + let a = unsafe { &*(self.value.get() as *const $atomic) }; + a.fetch_and(val, Ordering::AcqRel) + } + + /// Applies bitwise "or" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_or(16), 7); + /// assert_eq!(a.load(), 23); + /// ``` + #[inline] + pub fn fetch_or(&self, val: $t) -> $t { + let a = unsafe { &*(self.value.get() as *const $atomic) }; + a.fetch_or(val, Ordering::AcqRel) + } + + /// Applies bitwise "xor" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + #[doc = $example] + /// + /// assert_eq!(a.fetch_xor(2), 7); + /// assert_eq!(a.load(), 5); + /// ``` + #[inline] + pub fn fetch_xor(&self, val: $t) -> $t { + let a = unsafe { &*(self.value.get() as *const $atomic) }; + a.fetch_xor(val, Ordering::AcqRel) + } + } + }; +} + +#[cfg(has_atomic_u8)] +impl_arithmetic!(u8, atomic::AtomicU8, "let a = AtomicCell::new(7u8);"); +#[cfg(has_atomic_u8)] +impl_arithmetic!(i8, atomic::AtomicI8, "let a = AtomicCell::new(7i8);"); +#[cfg(has_atomic_u16)] +impl_arithmetic!(u16, atomic::AtomicU16, "let a = AtomicCell::new(7u16);"); +#[cfg(has_atomic_u16)] +impl_arithmetic!(i16, atomic::AtomicI16, "let a = AtomicCell::new(7i16);"); +#[cfg(has_atomic_u32)] +impl_arithmetic!(u32, atomic::AtomicU32, "let a = AtomicCell::new(7u32);"); +#[cfg(has_atomic_u32)] +impl_arithmetic!(i32, atomic::AtomicI32, "let a = AtomicCell::new(7i32);"); +#[cfg(has_atomic_u64)] +impl_arithmetic!(u64, atomic::AtomicU64, "let a = AtomicCell::new(7u64);"); +#[cfg(has_atomic_u64)] +impl_arithmetic!(i64, atomic::AtomicI64, "let a = AtomicCell::new(7i64);"); +#[cfg(has_atomic_u128)] +impl_arithmetic!(u128, atomic::AtomicU128, "let a = AtomicCell::new(7u128);"); +#[cfg(has_atomic_u128)] +impl_arithmetic!(i128, atomic::AtomicI128, "let a = AtomicCell::new(7i128);"); + +impl_arithmetic!( + usize, + atomic::AtomicUsize, + "let a = AtomicCell::new(7usize);" +); +impl_arithmetic!( + isize, + atomic::AtomicIsize, + "let a = AtomicCell::new(7isize);" +); + +impl AtomicCell { + /// Applies logical "and" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(true); + /// + /// assert_eq!(a.fetch_and(true), true); + /// assert_eq!(a.load(), true); + /// + /// assert_eq!(a.fetch_and(false), true); + /// assert_eq!(a.load(), false); + /// ``` + #[inline] + pub fn fetch_and(&self, val: bool) -> bool { + let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + a.fetch_and(val, Ordering::AcqRel) + } + + /// Applies logical "or" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(false); + /// + /// assert_eq!(a.fetch_or(false), false); + /// assert_eq!(a.load(), false); + /// + /// assert_eq!(a.fetch_or(true), false); + /// assert_eq!(a.load(), true); + /// ``` + #[inline] + pub fn fetch_or(&self, val: bool) -> bool { + let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + a.fetch_or(val, Ordering::AcqRel) + } + + /// Applies logical "xor" to the current value and returns the previous value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::atomic::AtomicCell; + /// + /// let a = AtomicCell::new(true); + /// + /// assert_eq!(a.fetch_xor(false), true); + /// assert_eq!(a.load(), true); + /// + /// assert_eq!(a.fetch_xor(true), true); + /// assert_eq!(a.load(), false); + /// ``` + #[inline] + pub fn fetch_xor(&self, val: bool) -> bool { + let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + a.fetch_xor(val, Ordering::AcqRel) + } +} + +impl Default for AtomicCell { + fn default() -> AtomicCell { + AtomicCell::new(T::default()) + } +} + +impl From for AtomicCell { + #[inline] + fn from(val: T) -> AtomicCell { + AtomicCell::new(val) + } +} + +impl fmt::Debug for AtomicCell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AtomicCell") + .field("value", &self.load()) + .finish() + } +} + +/// Returns `true` if values of type `A` can be transmuted into values of type `B`. +const fn can_transmute() -> bool { + // Sizes must be equal, but alignment of `A` must be greater or equal than that of `B`. + (mem::size_of::
() == mem::size_of::()) & (mem::align_of::() >= mem::align_of::()) +} + +/// Returns a reference to the global lock associated with the `AtomicCell` at address `addr`. +/// +/// This function is used to protect atomic data which doesn't fit into any of the primitive atomic +/// types in `std::sync::atomic`. Operations on such atomics must therefore use a global lock. +/// +/// However, there is not only one global lock but an array of many locks, and one of them is +/// picked based on the given address. Having many locks reduces contention and improves +/// scalability. +#[inline] +#[must_use] +fn lock(addr: usize) -> &'static SeqLock { + // The number of locks is a prime number because we want to make sure `addr % LEN` gets + // dispersed across all locks. + // + // Note that addresses are always aligned to some power of 2, depending on type `T` in + // `AtomicCell`. If `LEN` was an even number, then `addr % LEN` would be an even number, + // too, which means only half of the locks would get utilized! + // + // It is also possible for addresses to accidentally get aligned to a number that is not a + // power of 2. Consider this example: + // + // ``` + // #[repr(C)] + // struct Foo { + // a: AtomicCell, + // b: u8, + // c: u8, + // } + // ``` + // + // Now, if we have a slice of type `&[Foo]`, it is possible that field `a` in all items gets + // stored at addresses that are multiples of 3. It'd be too bad if `LEN` was divisible by 3. + // In order to protect from such cases, we simply choose a large prime number for `LEN`. + const LEN: usize = 97; + + static LOCKS: [SeqLock; LEN] = [ + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + SeqLock::new(), + ]; + + // If the modulus is a constant number, the compiler will use crazy math to transform this into + // a sequence of cheap arithmetic operations rather than using the slow modulo instruction. + &LOCKS[addr % LEN] +} + +/// An atomic `()`. +/// +/// All operations are noops. +struct AtomicUnit; + +impl AtomicUnit { + #[inline] + fn load(&self, _order: Ordering) {} + + #[inline] + fn store(&self, _val: (), _order: Ordering) {} + + #[inline] + fn swap(&self, _val: (), _order: Ordering) {} + + #[inline] + fn compare_exchange_weak( + &self, + _current: (), + _new: (), + _success: Ordering, + _failure: Ordering, + ) -> Result<(), ()> { + Ok(()) + } +} + +macro_rules! atomic { + // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`, + // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop. + (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => { + if can_transmute::<$t, $atomic>() { + let $a: &$atomic; + break $atomic_op; + } + }; + + // If values of type `$t` can be transmuted into values of a primitive atomic type, declares + // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes + // `$fallback_op`. + ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => { + loop { + atomic!(@check, $t, AtomicUnit, $a, $atomic_op); + atomic!(@check, $t, atomic::AtomicUsize, $a, $atomic_op); + + #[cfg(has_atomic_u8)] + atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); + #[cfg(has_atomic_u16)] + atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); + #[cfg(has_atomic_u32)] + atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op); + #[cfg(has_atomic_u64)] + atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op); + #[cfg(has_atomic_u128)] + atomic!(@check, $t, atomic::AtomicU128, $a, $atomic_op); + + break $fallback_op; + } + }; +} + +/// Returns `true` if operations on `AtomicCell` are lock-free. +const fn atomic_is_lock_free() -> bool { + // HACK(taiki-e): This is equivalent to `atomic! { T, _a, true, false }`, but can be used in const fn even in Rust 1.36. + let is_lock_free = can_transmute::() | can_transmute::(); + #[cfg(has_atomic_u8)] + let is_lock_free = is_lock_free | can_transmute::(); + #[cfg(has_atomic_u16)] + let is_lock_free = is_lock_free | can_transmute::(); + #[cfg(has_atomic_u32)] + let is_lock_free = is_lock_free | can_transmute::(); + #[cfg(has_atomic_u64)] + let is_lock_free = is_lock_free | can_transmute::(); + #[cfg(has_atomic_u128)] + let is_lock_free = is_lock_free | can_transmute::(); + is_lock_free +} + +/// Atomically reads data from `src`. +/// +/// This operation uses the `Acquire` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_load(src: *mut T) -> T +where + T: Copy, +{ + atomic! { + T, a, + { + a = &*(src as *const _ as *const _); + mem::transmute_copy(&a.load(Ordering::Acquire)) + }, + { + let lock = lock(src as usize); + + // Try doing an optimistic read first. + if let Some(stamp) = lock.optimistic_read() { + // We need a volatile read here because other threads might concurrently modify the + // value. In theory, data races are *always* UB, even if we use volatile reads and + // discard the data when a data race is detected. The proper solution would be to + // do atomic reads and atomic writes, but we can't atomically read and write all + // kinds of data since `AtomicU8` is not available on stable Rust yet. + let val = ptr::read_volatile(src); + + if lock.validate_read(stamp) { + return val; + } + } + + // Grab a regular write lock so that writers don't starve this load. + let guard = lock.write(); + let val = ptr::read(src); + // The value hasn't been changed. Drop the guard without incrementing the stamp. + guard.abort(); + val + } + } +} + +/// Atomically writes `val` to `dst`. +/// +/// This operation uses the `Release` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_store(dst: *mut T, val: T) { + atomic! { + T, a, + { + a = &*(dst as *const _ as *const _); + a.store(mem::transmute_copy(&val), Ordering::Release); + mem::forget(val); + }, + { + let _guard = lock(dst as usize).write(); + ptr::write(dst, val); + } + } +} + +/// Atomically swaps data at `dst` with `val`. +/// +/// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_swap(dst: *mut T, val: T) -> T { + atomic! { + T, a, + { + a = &*(dst as *const _ as *const _); + let res = mem::transmute_copy(&a.swap(mem::transmute_copy(&val), Ordering::AcqRel)); + mem::forget(val); + res + }, + { + let _guard = lock(dst as usize).write(); + ptr::replace(dst, val) + } + } +} + +/// Atomically compares data at `dst` to `current` and, if equal byte-for-byte, exchanges data at +/// `dst` with `new`. +/// +/// Returns the old value on success, or the current value at `dst` on failure. +/// +/// This operation uses the `AcqRel` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_compare_exchange_weak(dst: *mut T, mut current: T, new: T) -> Result +where + T: Copy + Eq, +{ + atomic! { + T, a, + { + a = &*(dst as *const _ as *const _); + let mut current_raw = mem::transmute_copy(¤t); + let new_raw = mem::transmute_copy(&new); + + loop { + match a.compare_exchange_weak( + current_raw, + new_raw, + Ordering::AcqRel, + Ordering::Acquire, + ) { + Ok(_) => break Ok(current), + Err(previous_raw) => { + let previous = mem::transmute_copy(&previous_raw); + + if !T::eq(&previous, ¤t) { + break Err(previous); + } + + // The compare-exchange operation has failed and didn't store `new`. The + // failure is either spurious, or `previous` was semantically equal to + // `current` but not byte-equal. Let's retry with `previous` as the new + // `current`. + current = previous; + current_raw = previous_raw; + } + } + } + }, + { + let guard = lock(dst as usize).write(); + + if T::eq(&*dst, ¤t) { + Ok(ptr::replace(dst, new)) + } else { + let val = ptr::read(dst); + // The value hasn't been changed. Drop the guard without incrementing the stamp. + guard.abort(); + Err(val) + } + } + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/consume.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/consume.rs new file mode 100644 index 0000000..584fc34 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/consume.rs @@ -0,0 +1,82 @@ +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +use core::sync::atomic::compiler_fence; +use core::sync::atomic::Ordering; + +/// Trait which allows reading from primitive atomic types with "consume" ordering. +pub trait AtomicConsume { + /// Type returned by `load_consume`. + type Val; + + /// Loads a value from the atomic using a "consume" memory ordering. + /// + /// This is similar to the "acquire" ordering, except that an ordering is + /// only guaranteed with operations that "depend on" the result of the load. + /// However consume loads are usually much faster than acquire loads on + /// architectures with a weak memory model since they don't require memory + /// fence instructions. + /// + /// The exact definition of "depend on" is a bit vague, but it works as you + /// would expect in practice since a lot of software, especially the Linux + /// kernel, rely on this behavior. + /// + /// This is currently only implemented on ARM and AArch64, where a fence + /// can be avoided. On other architectures this will fall back to a simple + /// `load(Ordering::Acquire)`. + fn load_consume(&self) -> Self::Val; +} + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +macro_rules! impl_consume { + () => { + #[inline] + fn load_consume(&self) -> Self::Val { + let result = self.load(Ordering::Relaxed); + compiler_fence(Ordering::Acquire); + result + } + }; +} + +#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] +macro_rules! impl_consume { + () => { + #[inline] + fn load_consume(&self) -> Self::Val { + self.load(Ordering::Acquire) + } + }; +} + +macro_rules! impl_atomic { + ($atomic:ident, $val:ty) => { + impl AtomicConsume for ::core::sync::atomic::$atomic { + type Val = $val; + impl_consume!(); + } + }; +} + +impl_atomic!(AtomicBool, bool); +impl_atomic!(AtomicUsize, usize); +impl_atomic!(AtomicIsize, isize); +#[cfg(has_atomic_u8)] +impl_atomic!(AtomicU8, u8); +#[cfg(has_atomic_u8)] +impl_atomic!(AtomicI8, i8); +#[cfg(has_atomic_u16)] +impl_atomic!(AtomicU16, u16); +#[cfg(has_atomic_u16)] +impl_atomic!(AtomicI16, i16); +#[cfg(has_atomic_u32)] +impl_atomic!(AtomicU32, u32); +#[cfg(has_atomic_u32)] +impl_atomic!(AtomicI32, i32); +#[cfg(has_atomic_u64)] +impl_atomic!(AtomicU64, u64); +#[cfg(has_atomic_u64)] +impl_atomic!(AtomicI64, i64); + +impl AtomicConsume for ::core::sync::atomic::AtomicPtr { + type Val = *mut T; + impl_consume!(); +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/mod.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/mod.rs new file mode 100644 index 0000000..7309c16 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/mod.rs @@ -0,0 +1,27 @@ +//! Atomic types. + +use cfg_if::cfg_if; + +cfg_if! { + // Use "wide" sequence lock if the pointer width <= 32 for preventing its counter against wrap + // around. + // + // We are ignoring too wide architectures (pointer width >= 256), since such a system will not + // appear in a conceivable future. + // + // In narrow architectures (pointer width <= 16), the counter is still <= 32-bit and may be + // vulnerable to wrap around. But it's mostly okay, since in such a primitive hardware, the + // counter will not be increased that fast. + if #[cfg(any(target_pointer_width = "64", target_pointer_width = "128"))] { + mod seq_lock; + } else { + #[path = "seq_lock_wide.rs"] + mod seq_lock; + } +} + +mod atomic_cell; +mod consume; + +pub use self::atomic_cell::AtomicCell; +pub use self::consume::AtomicConsume; diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/seq_lock.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/seq_lock.rs new file mode 100644 index 0000000..a423bc0 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/seq_lock.rs @@ -0,0 +1,112 @@ +use core::mem; +use core::sync::atomic::{self, AtomicUsize, Ordering}; + +use crate::Backoff; + +/// A simple stamped lock. +pub struct SeqLock { + /// The current state of the lock. + /// + /// All bits except the least significant one hold the current stamp. When locked, the state + /// equals 1 and doesn't contain a valid stamp. + state: AtomicUsize, +} + +impl SeqLock { + pub const fn new() -> Self { + Self { + state: AtomicUsize::new(0), + } + } + + /// If not locked, returns the current stamp. + /// + /// This method should be called before optimistic reads. + #[inline] + pub fn optimistic_read(&self) -> Option { + let state = self.state.load(Ordering::Acquire); + if state == 1 { + None + } else { + Some(state) + } + } + + /// Returns `true` if the current stamp is equal to `stamp`. + /// + /// This method should be called after optimistic reads to check whether they are valid. The + /// argument `stamp` should correspond to the one returned by method `optimistic_read`. + #[inline] + pub fn validate_read(&self, stamp: usize) -> bool { + atomic::fence(Ordering::Acquire); + self.state.load(Ordering::Relaxed) == stamp + } + + /// Grabs the lock for writing. + #[inline] + pub fn write(&'static self) -> SeqLockWriteGuard { + let backoff = Backoff::new(); + loop { + let previous = self.state.swap(1, Ordering::Acquire); + + if previous != 1 { + atomic::fence(Ordering::Release); + + return SeqLockWriteGuard { + lock: self, + state: previous, + }; + } + + backoff.snooze(); + } + } +} + +/// An RAII guard that releases the lock and increments the stamp when dropped. +pub struct SeqLockWriteGuard { + /// The parent lock. + lock: &'static SeqLock, + + /// The stamp before locking. + state: usize, +} + +impl SeqLockWriteGuard { + /// Releases the lock without incrementing the stamp. + #[inline] + pub fn abort(self) { + self.lock.state.store(self.state, Ordering::Release); + + // We specifically don't want to call drop(), since that's + // what increments the stamp. + mem::forget(self); + } +} + +impl Drop for SeqLockWriteGuard { + #[inline] + fn drop(&mut self) { + // Release the lock and increment the stamp. + self.lock + .state + .store(self.state.wrapping_add(2), Ordering::Release); + } +} + +#[cfg(test)] +mod tests { + use super::SeqLock; + + #[test] + fn test_abort() { + static LK: SeqLock = SeqLock::new(); + let before = LK.optimistic_read().unwrap(); + { + let guard = LK.write(); + guard.abort(); + } + let after = LK.optimistic_read().unwrap(); + assert_eq!(before, after, "aborted write does not update the stamp"); + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/seq_lock_wide.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/seq_lock_wide.rs new file mode 100644 index 0000000..871a93d --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/atomic/seq_lock_wide.rs @@ -0,0 +1,155 @@ +use core::mem; +use core::sync::atomic::{self, AtomicUsize, Ordering}; + +use crate::Backoff; + +/// A simple stamped lock. +/// +/// The state is represented as two `AtomicUsize`: `state_hi` for high bits and `state_lo` for low +/// bits. +pub struct SeqLock { + /// The high bits of the current state of the lock. + state_hi: AtomicUsize, + + /// The low bits of the current state of the lock. + /// + /// All bits except the least significant one hold the current stamp. When locked, the state_lo + /// equals 1 and doesn't contain a valid stamp. + state_lo: AtomicUsize, +} + +impl SeqLock { + pub const fn new() -> Self { + Self { + state_hi: AtomicUsize::new(0), + state_lo: AtomicUsize::new(0), + } + } + + /// If not locked, returns the current stamp. + /// + /// This method should be called before optimistic reads. + #[inline] + pub fn optimistic_read(&self) -> Option<(usize, usize)> { + // The acquire loads from `state_hi` and `state_lo` synchronize with the release stores in + // `SeqLockWriteGuard::drop`. + // + // As a consequence, we can make sure that (1) all writes within the era of `state_hi - 1` + // happens before now; and therefore, (2) if `state_lo` is even, all writes within the + // critical section of (`state_hi`, `state_lo`) happens before now. + let state_hi = self.state_hi.load(Ordering::Acquire); + let state_lo = self.state_lo.load(Ordering::Acquire); + if state_lo == 1 { + None + } else { + Some((state_hi, state_lo)) + } + } + + /// Returns `true` if the current stamp is equal to `stamp`. + /// + /// This method should be called after optimistic reads to check whether they are valid. The + /// argument `stamp` should correspond to the one returned by method `optimistic_read`. + #[inline] + pub fn validate_read(&self, stamp: (usize, usize)) -> bool { + // Thanks to the fence, if we're noticing any modification to the data at the critical + // section of `(a, b)`, then the critical section's write of 1 to state_lo should be + // visible. + atomic::fence(Ordering::Acquire); + + // So if `state_lo` coincides with `stamp.1`, then either (1) we're noticing no modification + // to the data after the critical section of `(stamp.0, stamp.1)`, or (2) `state_lo` wrapped + // around. + // + // If (2) is the case, the acquire ordering ensures we see the new value of `state_hi`. + let state_lo = self.state_lo.load(Ordering::Acquire); + + // If (2) is the case and `state_hi` coincides with `stamp.0`, then `state_hi` also wrapped + // around, which we give up to correctly validate the read. + let state_hi = self.state_hi.load(Ordering::Relaxed); + + // Except for the case that both `state_hi` and `state_lo` wrapped around, the following + // condition implies that we're noticing no modification to the data after the critical + // section of `(stamp.0, stamp.1)`. + (state_hi, state_lo) == stamp + } + + /// Grabs the lock for writing. + #[inline] + pub fn write(&'static self) -> SeqLockWriteGuard { + let backoff = Backoff::new(); + loop { + let previous = self.state_lo.swap(1, Ordering::Acquire); + + if previous != 1 { + // To synchronize with the acquire fence in `validate_read` via any modification to + // the data at the critical section of `(state_hi, previous)`. + atomic::fence(Ordering::Release); + + return SeqLockWriteGuard { + lock: self, + state_lo: previous, + }; + } + + backoff.snooze(); + } + } +} + +/// An RAII guard that releases the lock and increments the stamp when dropped. +pub struct SeqLockWriteGuard { + /// The parent lock. + lock: &'static SeqLock, + + /// The stamp before locking. + state_lo: usize, +} + +impl SeqLockWriteGuard { + /// Releases the lock without incrementing the stamp. + #[inline] + pub fn abort(self) { + self.lock.state_lo.store(self.state_lo, Ordering::Release); + mem::forget(self); + } +} + +impl Drop for SeqLockWriteGuard { + #[inline] + fn drop(&mut self) { + let state_lo = self.state_lo.wrapping_add(2); + + // Increase the high bits if the low bits wrap around. + // + // Release ordering for synchronizing with `optimistic_read`. + if state_lo == 0 { + let state_hi = self.lock.state_hi.load(Ordering::Relaxed); + self.lock + .state_hi + .store(state_hi.wrapping_add(1), Ordering::Release); + } + + // Release the lock and increment the stamp. + // + // Release ordering for synchronizing with `optimistic_read`. + self.lock.state_lo.store(state_lo, Ordering::Release); + } +} + +#[cfg(test)] +mod tests { + use super::SeqLock; + + #[test] + fn test_abort() { + static LK: SeqLock = SeqLock::new(); + let before = LK.optimistic_read().unwrap(); + { + let guard = LK.write(); + guard.abort(); + } + let after = LK.optimistic_read().unwrap(); + assert_eq!(before, after, "aborted write does not update the stamp"); + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/backoff.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/backoff.rs new file mode 100644 index 0000000..2391dd1 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/backoff.rs @@ -0,0 +1,285 @@ +use core::cell::Cell; +use core::fmt; +use core::sync::atomic; + +const SPIN_LIMIT: u32 = 6; +const YIELD_LIMIT: u32 = 10; + +/// Performs exponential backoff in spin loops. +/// +/// Backing off in spin loops reduces contention and improves overall performance. +/// +/// This primitive can execute *YIELD* and *PAUSE* instructions, yield the current thread to the OS +/// scheduler, and tell when is a good time to block the thread using a different synchronization +/// mechanism. Each step of the back off procedure takes roughly twice as long as the previous +/// step. +/// +/// # Examples +/// +/// Backing off in a lock-free loop: +/// +/// ``` +/// use crossbeam_utils::Backoff; +/// use std::sync::atomic::AtomicUsize; +/// use std::sync::atomic::Ordering::SeqCst; +/// +/// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { +/// let backoff = Backoff::new(); +/// loop { +/// let val = a.load(SeqCst); +/// if a.compare_and_swap(val, val.wrapping_mul(b), SeqCst) == val { +/// return val; +/// } +/// backoff.spin(); +/// } +/// } +/// ``` +/// +/// Waiting for an [`AtomicBool`] to become `true`: +/// +/// ``` +/// use crossbeam_utils::Backoff; +/// use std::sync::atomic::AtomicBool; +/// use std::sync::atomic::Ordering::SeqCst; +/// +/// fn spin_wait(ready: &AtomicBool) { +/// let backoff = Backoff::new(); +/// while !ready.load(SeqCst) { +/// backoff.snooze(); +/// } +/// } +/// ``` +/// +/// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait. +/// Note that whoever sets the atomic variable to `true` must notify the parked thread by calling +/// [`unpark()`]: +/// +/// ``` +/// use crossbeam_utils::Backoff; +/// use std::sync::atomic::AtomicBool; +/// use std::sync::atomic::Ordering::SeqCst; +/// use std::thread; +/// +/// fn blocking_wait(ready: &AtomicBool) { +/// let backoff = Backoff::new(); +/// while !ready.load(SeqCst) { +/// if backoff.is_completed() { +/// thread::park(); +/// } else { +/// backoff.snooze(); +/// } +/// } +/// } +/// ``` +/// +/// [`is_completed`]: Backoff::is_completed +/// [`std::thread::park()`]: std::thread::park +/// [`Condvar`]: std::sync::Condvar +/// [`AtomicBool`]: std::sync::atomic::AtomicBool +/// [`unpark()`]: std::thread::Thread::unpark +pub struct Backoff { + step: Cell, +} + +impl Backoff { + /// Creates a new `Backoff`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// + /// let backoff = Backoff::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Backoff { step: Cell::new(0) } + } + + /// Resets the `Backoff`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// + /// let backoff = Backoff::new(); + /// backoff.reset(); + /// ``` + #[inline] + pub fn reset(&self) { + self.step.set(0); + } + + /// Backs off in a lock-free loop. + /// + /// This method should be used when we need to retry an operation because another thread made + /// progress. + /// + /// The processor may yield using the *YIELD* or *PAUSE* instruction. + /// + /// # Examples + /// + /// Backing off in a lock-free loop: + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// use std::sync::atomic::AtomicUsize; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { + /// let backoff = Backoff::new(); + /// loop { + /// let val = a.load(SeqCst); + /// if a.compare_and_swap(val, val.wrapping_mul(b), SeqCst) == val { + /// return val; + /// } + /// backoff.spin(); + /// } + /// } + /// + /// let a = AtomicUsize::new(7); + /// assert_eq!(fetch_mul(&a, 8), 7); + /// assert_eq!(a.load(SeqCst), 56); + /// ``` + #[inline] + pub fn spin(&self) { + for _ in 0..1 << self.step.get().min(SPIN_LIMIT) { + atomic::spin_loop_hint(); + } + + if self.step.get() <= SPIN_LIMIT { + self.step.set(self.step.get() + 1); + } + } + + /// Backs off in a blocking loop. + /// + /// This method should be used when we need to wait for another thread to make progress. + /// + /// The processor may yield using the *YIELD* or *PAUSE* instruction and the current thread + /// may yield by giving up a timeslice to the OS scheduler. + /// + /// In `#[no_std]` environments, this method is equivalent to [`spin`]. + /// + /// If possible, use [`is_completed`] to check when it is advised to stop using backoff and + /// block the current thread using a different synchronization mechanism instead. + /// + /// [`spin`]: Backoff::spin + /// [`is_completed`]: Backoff::is_completed + /// + /// # Examples + /// + /// Waiting for an [`AtomicBool`] to become `true`: + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// use std::sync::Arc; + /// use std::sync::atomic::AtomicBool; + /// use std::sync::atomic::Ordering::SeqCst; + /// use std::thread; + /// use std::time::Duration; + /// + /// fn spin_wait(ready: &AtomicBool) { + /// let backoff = Backoff::new(); + /// while !ready.load(SeqCst) { + /// backoff.snooze(); + /// } + /// } + /// + /// let ready = Arc::new(AtomicBool::new(false)); + /// let ready2 = ready.clone(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// ready2.store(true, SeqCst); + /// }); + /// + /// assert_eq!(ready.load(SeqCst), false); + /// spin_wait(&ready); + /// assert_eq!(ready.load(SeqCst), true); + /// ``` + /// + /// [`AtomicBool`]: std::sync::atomic::AtomicBool + #[inline] + pub fn snooze(&self) { + if self.step.get() <= SPIN_LIMIT { + for _ in 0..1 << self.step.get() { + atomic::spin_loop_hint(); + } + } else { + #[cfg(not(feature = "std"))] + for _ in 0..1 << self.step.get() { + atomic::spin_loop_hint(); + } + + #[cfg(feature = "std")] + ::std::thread::yield_now(); + } + + if self.step.get() <= YIELD_LIMIT { + self.step.set(self.step.get() + 1); + } + } + + /// Returns `true` if exponential backoff has completed and blocking the thread is advised. + /// + /// # Examples + /// + /// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait: + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// use std::sync::Arc; + /// use std::sync::atomic::AtomicBool; + /// use std::sync::atomic::Ordering::SeqCst; + /// use std::thread; + /// use std::time::Duration; + /// + /// fn blocking_wait(ready: &AtomicBool) { + /// let backoff = Backoff::new(); + /// while !ready.load(SeqCst) { + /// if backoff.is_completed() { + /// thread::park(); + /// } else { + /// backoff.snooze(); + /// } + /// } + /// } + /// + /// let ready = Arc::new(AtomicBool::new(false)); + /// let ready2 = ready.clone(); + /// let waiter = thread::current(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// ready2.store(true, SeqCst); + /// waiter.unpark(); + /// }); + /// + /// assert_eq!(ready.load(SeqCst), false); + /// blocking_wait(&ready); + /// assert_eq!(ready.load(SeqCst), true); + /// ``` + /// + /// [`AtomicBool`]: std::sync::atomic::AtomicBool + #[inline] + pub fn is_completed(&self) -> bool { + self.step.get() > YIELD_LIMIT + } +} + +impl fmt::Debug for Backoff { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Backoff") + .field("step", &self.step) + .field("is_completed", &self.is_completed()) + .finish() + } +} + +impl Default for Backoff { + fn default() -> Backoff { + Backoff::new() + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/cache_padded.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/cache_padded.rs new file mode 100644 index 0000000..62c686b --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/cache_padded.rs @@ -0,0 +1,139 @@ +use core::fmt; +use core::ops::{Deref, DerefMut}; + +/// Pads and aligns a value to the length of a cache line. +/// +/// In concurrent programming, sometimes it is desirable to make sure commonly accessed pieces of +/// data are not placed into the same cache line. Updating an atomic value invalidates the whole +/// cache line it belongs to, which makes the next access to the same cache line slower for other +/// CPU cores. Use `CachePadded` to ensure updating one piece of data doesn't invalidate other +/// cached data. +/// +/// # Size and alignment +/// +/// Cache lines are assumed to be N bytes long, depending on the architecture: +/// +/// * On x86-64 and aarch64, N = 128. +/// * On all others, N = 64. +/// +/// Note that N is just a reasonable guess and is not guaranteed to match the actual cache line +/// length of the machine the program is running on. On modern Intel architectures, spatial +/// prefetcher is pulling pairs of 64-byte cache lines at a time, so we pessimistically assume that +/// cache lines are 128 bytes long. +/// +/// The size of `CachePadded` is the smallest multiple of N bytes large enough to accommodate +/// a value of type `T`. +/// +/// The alignment of `CachePadded` is the maximum of N bytes and the alignment of `T`. +/// +/// # Examples +/// +/// Alignment and padding: +/// +/// ``` +/// use crossbeam_utils::CachePadded; +/// +/// let array = [CachePadded::new(1i8), CachePadded::new(2i8)]; +/// let addr1 = &*array[0] as *const i8 as usize; +/// let addr2 = &*array[1] as *const i8 as usize; +/// +/// assert!(addr2 - addr1 >= 64); +/// assert_eq!(addr1 % 64, 0); +/// assert_eq!(addr2 % 64, 0); +/// ``` +/// +/// When building a concurrent queue with a head and a tail index, it is wise to place them in +/// different cache lines so that concurrent threads pushing and popping elements don't invalidate +/// each other's cache lines: +/// +/// ``` +/// use crossbeam_utils::CachePadded; +/// use std::sync::atomic::AtomicUsize; +/// +/// struct Queue { +/// head: CachePadded, +/// tail: CachePadded, +/// buffer: *mut T, +/// } +/// ``` +#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)] +// Starting from Intel's Sandy Bridge, spatial prefetcher is now pulling pairs of 64-byte cache +// lines at a time, so we have to align to 128 bytes rather than 64. +// +// Sources: +// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf +// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107 +// +// ARM's big.LITTLE architecture has asymmetric cores and "big" cores have 128 byte cache line size +// Sources: +// - https://www.mono-project.com/news/2016/09/12/arm64-icache/ +// +#[cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), repr(align(128)))] +#[cfg_attr( + not(any(target_arch = "x86_64", target_arch = "aarch64")), + repr(align(64)) +)] +pub struct CachePadded { + value: T, +} + +unsafe impl Send for CachePadded {} +unsafe impl Sync for CachePadded {} + +impl CachePadded { + /// Pads and aligns a value to the length of a cache line. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::CachePadded; + /// + /// let padded_value = CachePadded::new(1); + /// ``` + pub const fn new(t: T) -> CachePadded { + CachePadded:: { value: t } + } + + /// Returns the inner value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::CachePadded; + /// + /// let padded_value = CachePadded::new(7); + /// let value = padded_value.into_inner(); + /// assert_eq!(value, 7); + /// ``` + pub fn into_inner(self) -> T { + self.value + } +} + +impl Deref for CachePadded { + type Target = T; + + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for CachePadded { + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl fmt::Debug for CachePadded { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CachePadded") + .field("value", &self.value) + .finish() + } +} + +impl From for CachePadded { + fn from(t: T) -> Self { + CachePadded::new(t) + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/lib.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/lib.rs new file mode 100644 index 0000000..f2bd460 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/lib.rs @@ -0,0 +1,56 @@ +//! Miscellaneous tools for concurrent programming. +//! +//! ## Atomics +//! +//! * [`AtomicCell`], a thread-safe mutable memory location. +//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. +//! +//! ## Thread synchronization +//! +//! * [`Parker`], a thread parking primitive. +//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. +//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. +//! +//! ## Utilities +//! +//! * [`Backoff`], for exponential backoff in spin loops. +//! * [`CachePadded`], for padding and aligning a value to the length of a cache line. +//! * [`scope`], for spawning threads that borrow local variables from the stack. +//! +//! [`AtomicCell`]: atomic::AtomicCell +//! [`AtomicConsume`]: atomic::AtomicConsume +//! [`Parker`]: sync::Parker +//! [`ShardedLock`]: sync::ShardedLock +//! [`WaitGroup`]: sync::WaitGroup +//! [`scope`]: thread::scope + +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms), + allow(dead_code, unused_assignments, unused_variables) + ) +))] +#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] +// matches! requires Rust 1.42 +#![allow(clippy::match_like_matches_macro)] + +#[cfg_attr(feature = "nightly", cfg(target_has_atomic = "ptr"))] +pub mod atomic; + +mod cache_padded; +pub use crate::cache_padded::CachePadded; + +mod backoff; +pub use crate::backoff::Backoff; + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "std")] { + pub mod sync; + pub mod thread; + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/mod.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/mod.rs new file mode 100644 index 0000000..fd400d7 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/mod.rs @@ -0,0 +1,13 @@ +//! Thread synchronization primitives. +//! +//! * [`Parker`], a thread parking primitive. +//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. +//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. + +mod parker; +mod sharded_lock; +mod wait_group; + +pub use self::parker::{Parker, Unparker}; +pub use self::sharded_lock::{ShardedLock, ShardedLockReadGuard, ShardedLockWriteGuard}; +pub use self::wait_group::WaitGroup; diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/parker.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/parker.rs new file mode 100644 index 0000000..fc13d2e --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/parker.rs @@ -0,0 +1,397 @@ +use std::fmt; +use std::marker::PhantomData; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; +use std::sync::{Arc, Condvar, Mutex}; +use std::time::Duration; + +/// A thread parking primitive. +/// +/// Conceptually, each `Parker` has an associated token which is initially not present: +/// +/// * The [`park`] method blocks the current thread unless or until the token is available, at +/// which point it automatically consumes the token. It may also return *spuriously*, without +/// consuming the token. +/// +/// * The [`park_timeout`] method works the same as [`park`], but blocks for a specified maximum +/// time. +/// +/// * The [`unpark`] method atomically makes the token available if it wasn't already. Because the +/// token is initially absent, [`unpark`] followed by [`park`] will result in the second call +/// returning immediately. +/// +/// In other words, each `Parker` acts a bit like a spinlock that can be locked and unlocked using +/// [`park`] and [`unpark`]. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_utils::sync::Parker; +/// +/// let p = Parker::new(); +/// let u = p.unparker().clone(); +/// +/// // Make the token available. +/// u.unpark(); +/// // Wakes up immediately and consumes the token. +/// p.park(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// u.unpark(); +/// }); +/// +/// // Wakes up when `u.unpark()` provides the token, but may also wake up +/// // spuriously before that without consuming the token. +/// p.park(); +/// ``` +/// +/// [`park`]: Parker::park +/// [`park_timeout`]: Parker::park_timeout +/// [`unpark`]: Unparker::unpark +pub struct Parker { + unparker: Unparker, + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for Parker {} + +impl Default for Parker { + fn default() -> Self { + Self { + unparker: Unparker { + inner: Arc::new(Inner { + state: AtomicUsize::new(EMPTY), + lock: Mutex::new(()), + cvar: Condvar::new(), + }), + }, + _marker: PhantomData, + } + } +} + +impl Parker { + /// Creates a new `Parker`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// ``` + /// + pub fn new() -> Parker { + Self::default() + } + + /// Blocks the current thread until the token is made available. + /// + /// A call to `park` may wake up spuriously without consuming the token, and callers should be + /// prepared for this possibility. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// // Make the token available. + /// u.unpark(); + /// + /// // Wakes up immediately and consumes the token. + /// p.park(); + /// ``` + pub fn park(&self) { + self.unparker.inner.park(None); + } + + /// Blocks the current thread until the token is made available, but only for a limited time. + /// + /// A call to `park_timeout` may wake up spuriously without consuming the token, and callers + /// should be prepared for this possibility. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// + /// // Waits for the token to become available, but will not wait longer than 500 ms. + /// p.park_timeout(Duration::from_millis(500)); + /// ``` + pub fn park_timeout(&self, timeout: Duration) { + self.unparker.inner.park(Some(timeout)); + } + + /// Returns a reference to an associated [`Unparker`]. + /// + /// The returned [`Unparker`] doesn't have to be used by reference - it can also be cloned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// // Make the token available. + /// u.unpark(); + /// // Wakes up immediately and consumes the token. + /// p.park(); + /// ``` + /// + /// [`park`]: Parker::park + /// [`park_timeout`]: Parker::park_timeout + pub fn unparker(&self) -> &Unparker { + &self.unparker + } + + /// Converts a `Parker` into a raw pointer. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// let raw = Parker::into_raw(p); + /// ``` + pub fn into_raw(this: Parker) -> *const () { + Unparker::into_raw(this.unparker) + } + + /// Converts a raw pointer into a `Parker`. + /// + /// # Safety + /// + /// This method is safe to use only with pointers returned by [`Parker::into_raw`]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// let raw = Parker::into_raw(p); + /// let p = unsafe { Parker::from_raw(raw) }; + /// ``` + pub unsafe fn from_raw(ptr: *const ()) -> Parker { + Parker { + unparker: Unparker::from_raw(ptr), + _marker: PhantomData, + } + } +} + +impl fmt::Debug for Parker { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Parker { .. }") + } +} + +/// Unparks a thread parked by the associated [`Parker`]. +pub struct Unparker { + inner: Arc, +} + +unsafe impl Send for Unparker {} +unsafe impl Sync for Unparker {} + +impl Unparker { + /// Atomically makes the token available if it is not already. + /// + /// This method will wake up the thread blocked on [`park`] or [`park_timeout`], if there is + /// any. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// u.unpark(); + /// }); + /// + /// // Wakes up when `u.unpark()` provides the token, but may also wake up + /// // spuriously before that without consuming the token. + /// p.park(); + /// ``` + /// + /// [`park`]: Parker::park + /// [`park_timeout`]: Parker::park_timeout + pub fn unpark(&self) { + self.inner.unpark() + } + + /// Converts an `Unparker` into a raw pointer. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::{Parker, Unparker}; + /// + /// let p = Parker::new(); + /// let u = p.unparker().clone(); + /// let raw = Unparker::into_raw(u); + /// ``` + pub fn into_raw(this: Unparker) -> *const () { + Arc::into_raw(this.inner) as *const () + } + + /// Converts a raw pointer into an `Unparker`. + /// + /// # Safety + /// + /// This method is safe to use only with pointers returned by [`Unparker::into_raw`]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::{Parker, Unparker}; + /// + /// let p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// let raw = Unparker::into_raw(u); + /// let u = unsafe { Unparker::from_raw(raw) }; + /// ``` + pub unsafe fn from_raw(ptr: *const ()) -> Unparker { + Unparker { + inner: Arc::from_raw(ptr as *const Inner), + } + } +} + +impl fmt::Debug for Unparker { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Unparker { .. }") + } +} + +impl Clone for Unparker { + fn clone(&self) -> Unparker { + Unparker { + inner: self.inner.clone(), + } + } +} + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +struct Inner { + state: AtomicUsize, + lock: Mutex<()>, + cvar: Condvar, +} + +impl Inner { + fn park(&self, timeout: Option) { + // If we were previously notified then we consume this notification and return quickly. + if self + .state + .compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) + .is_ok() + { + return; + } + + // If the timeout is zero, then there is no need to actually block. + if let Some(ref dur) = timeout { + if *dur == Duration::from_millis(0) { + return; + } + } + + // Otherwise we need to coordinate going to sleep. + let mut m = self.lock.lock().unwrap(); + + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + // Consume this notification to avoid spurious wakeups in the next park. + Err(NOTIFIED) => { + // We must read `state` here, even though we know it will be `NOTIFIED`. This is + // because `unpark` may have been called again since we read `NOTIFIED` in the + // `compare_exchange` above. We must perform an acquire operation that synchronizes + // with that `unpark` to observe any writes it made before the call to `unpark`. To + // do that we must read from the write it made to `state`. + let old = self.state.swap(EMPTY, SeqCst); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } + Err(n) => panic!("inconsistent park_timeout state: {}", n), + } + + match timeout { + None => { + loop { + // Block the current thread on the conditional variable. + m = self.cvar.wait(m).unwrap(); + + if self + .state + .compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) + .is_ok() + { + // got a notification + return; + } + + // spurious wakeup, go back to sleep + } + } + Some(timeout) => { + // Wait with a timeout, and if we spuriously wake up or otherwise wake up from a + // notification we just want to unconditionally set `state` back to `EMPTY`, either + // consuming a notification or un-flagging ourselves as parked. + let (_m, _result) = self.cvar.wait_timeout(m, timeout).unwrap(); + + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => {} // got a notification + PARKED => {} // no notification + n => panic!("inconsistent park_timeout state: {}", n), + } + } + } + } + + pub fn unpark(&self) { + // To ensure the unparked thread will observe any writes we made before this call, we must + // perform a release operation that `park` can synchronize with. To do that we must write + // `NOTIFIED` even if `state` is already `NOTIFIED`. That is why this must be a swap rather + // than a compare-and-swap that returns if it reads `NOTIFIED` on failure. + match self.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), + } + + // There is a period between when the parked thread sets `state` to `PARKED` (or last + // checked `state` in the case of a spurious wakeup) and when it actually waits on `cvar`. + // If we were to notify during this period it would be ignored and then when the parked + // thread went to sleep it would never wake up. Fortunately, it has `lock` locked at this + // stage so we can acquire `lock` to wait until it is ready to receive the notification. + // + // Releasing `lock` before the call to `notify_one` means that when the parked thread wakes + // it doesn't get woken only to have to wait for us to release `lock`. + drop(self.lock.lock().unwrap()); + self.cvar.notify_one(); + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/sharded_lock.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/sharded_lock.rs new file mode 100644 index 0000000..163d34c --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/sharded_lock.rs @@ -0,0 +1,630 @@ +use std::cell::UnsafeCell; +use std::collections::HashMap; +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::sync::{LockResult, PoisonError, TryLockError, TryLockResult}; +use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::thread::{self, ThreadId}; + +use crate::CachePadded; +use lazy_static::lazy_static; + +/// The number of shards per sharded lock. Must be a power of two. +const NUM_SHARDS: usize = 8; + +/// A shard containing a single reader-writer lock. +struct Shard { + /// The inner reader-writer lock. + lock: RwLock<()>, + + /// The write-guard keeping this shard locked. + /// + /// Write operations will lock each shard and store the guard here. These guards get dropped at + /// the same time the big guard is dropped. + write_guard: UnsafeCell>>, +} + +/// A sharded reader-writer lock. +/// +/// This lock is equivalent to [`RwLock`], except read operations are faster and write operations +/// are slower. +/// +/// A `ShardedLock` is internally made of a list of *shards*, each being a [`RwLock`] occupying a +/// single cache line. Read operations will pick one of the shards depending on the current thread +/// and lock it. Write operations need to lock all shards in succession. +/// +/// By splitting the lock into shards, concurrent read operations will in most cases choose +/// different shards and thus update different cache lines, which is good for scalability. However, +/// write operations need to do more work and are therefore slower than usual. +/// +/// The priority policy of the lock is dependent on the underlying operating system's +/// implementation, and this type does not guarantee that any particular policy will be used. +/// +/// # Poisoning +/// +/// A `ShardedLock`, like [`RwLock`], will become poisoned on a panic. Note that it may only be +/// poisoned if a panic occurs while a write operation is in progress. If a panic occurs in any +/// read operation, the lock will not be poisoned. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::sync::ShardedLock; +/// +/// let lock = ShardedLock::new(5); +/// +/// // Any number of read locks can be held at once. +/// { +/// let r1 = lock.read().unwrap(); +/// let r2 = lock.read().unwrap(); +/// assert_eq!(*r1, 5); +/// assert_eq!(*r2, 5); +/// } // Read locks are dropped at this point. +/// +/// // However, only one write lock may be held. +/// { +/// let mut w = lock.write().unwrap(); +/// *w += 1; +/// assert_eq!(*w, 6); +/// } // Write lock is dropped here. +/// ``` +/// +/// [`RwLock`]: std::sync::RwLock +pub struct ShardedLock { + /// A list of locks protecting the internal data. + shards: Box<[CachePadded]>, + + /// The internal data. + value: UnsafeCell, +} + +unsafe impl Send for ShardedLock {} +unsafe impl Sync for ShardedLock {} + +impl UnwindSafe for ShardedLock {} +impl RefUnwindSafe for ShardedLock {} + +impl ShardedLock { + /// Creates a new sharded reader-writer lock. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(5); + /// ``` + pub fn new(value: T) -> ShardedLock { + ShardedLock { + shards: (0..NUM_SHARDS) + .map(|_| { + CachePadded::new(Shard { + lock: RwLock::new(()), + write_guard: UnsafeCell::new(None), + }) + }) + .collect::>(), + value: UnsafeCell::new(value), + } + } + + /// Consumes this lock, returning the underlying data. + /// + /// # Errors + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(String::new()); + /// { + /// let mut s = lock.write().unwrap(); + /// *s = "modified".to_owned(); + /// } + /// assert_eq!(lock.into_inner().unwrap(), "modified"); + /// ``` + pub fn into_inner(self) -> LockResult { + let is_poisoned = self.is_poisoned(); + let inner = self.value.into_inner(); + + if is_poisoned { + Err(PoisonError::new(inner)) + } else { + Ok(inner) + } + } +} + +impl ShardedLock { + /// Returns `true` if the lock is poisoned. + /// + /// If another thread can still access the lock, it may become poisoned at any time. A `false` + /// result should not be trusted without additional synchronization. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let lock = Arc::new(ShardedLock::new(0)); + /// let c_lock = lock.clone(); + /// + /// let _ = thread::spawn(move || { + /// let _lock = c_lock.write().unwrap(); + /// panic!(); // the lock gets poisoned + /// }).join(); + /// assert_eq!(lock.is_poisoned(), true); + /// ``` + pub fn is_poisoned(&self) -> bool { + self.shards[0].lock.is_poisoned() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the lock mutably, no actual locking needs to take place. + /// + /// # Errors + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let mut lock = ShardedLock::new(0); + /// *lock.get_mut().unwrap() = 10; + /// assert_eq!(*lock.read().unwrap(), 10); + /// ``` + pub fn get_mut(&mut self) -> LockResult<&mut T> { + let is_poisoned = self.is_poisoned(); + let inner = unsafe { &mut *self.value.get() }; + + if is_poisoned { + Err(PoisonError::new(inner)) + } else { + Ok(inner) + } + } + + /// Attempts to acquire this lock with shared read access. + /// + /// If the access could not be granted at this time, an error is returned. Otherwise, a guard + /// is returned which will release the shared access when it is dropped. This method does not + /// provide any guarantees with respect to the ordering of whether contentious readers or + /// writers will acquire the lock first. + /// + /// # Errors + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(1); + /// + /// match lock.try_read() { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; + /// ``` + pub fn try_read(&self) -> TryLockResult> { + // Take the current thread index and map it to a shard index. Thread indices will tend to + // distribute shards among threads equally, thus reducing contention due to read-locking. + let current_index = current_index().unwrap_or(0); + let shard_index = current_index & (self.shards.len() - 1); + + match self.shards[shard_index].lock.try_read() { + Ok(guard) => Ok(ShardedLockReadGuard { + lock: self, + _guard: guard, + _marker: PhantomData, + }), + Err(TryLockError::Poisoned(err)) => { + let guard = ShardedLockReadGuard { + lock: self, + _guard: err.into_inner(), + _marker: PhantomData, + }; + Err(TryLockError::Poisoned(PoisonError::new(guard))) + } + Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock), + } + } + + /// Locks with shared read access, blocking the current thread until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which hold the lock. + /// There may be other readers currently inside the lock when this method returns. This method + /// does not provide any guarantees with respect to the ordering of whether contentious readers + /// or writers will acquire the lock first. + /// + /// Returns a guard which will release the shared access when dropped. + /// + /// # Errors + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Panics + /// + /// This method might panic when called if the lock is already held by the current thread. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let lock = Arc::new(ShardedLock::new(1)); + /// let c_lock = lock.clone(); + /// + /// let n = lock.read().unwrap(); + /// assert_eq!(*n, 1); + /// + /// thread::spawn(move || { + /// let r = c_lock.read(); + /// assert!(r.is_ok()); + /// }).join().unwrap(); + /// ``` + pub fn read(&self) -> LockResult> { + // Take the current thread index and map it to a shard index. Thread indices will tend to + // distribute shards among threads equally, thus reducing contention due to read-locking. + let current_index = current_index().unwrap_or(0); + let shard_index = current_index & (self.shards.len() - 1); + + match self.shards[shard_index].lock.read() { + Ok(guard) => Ok(ShardedLockReadGuard { + lock: self, + _guard: guard, + _marker: PhantomData, + }), + Err(err) => Err(PoisonError::new(ShardedLockReadGuard { + lock: self, + _guard: err.into_inner(), + _marker: PhantomData, + })), + } + } + + /// Attempts to acquire this lock with exclusive write access. + /// + /// If the access could not be granted at this time, an error is returned. Otherwise, a guard + /// is returned which will release the exclusive access when it is dropped. This method does + /// not provide any guarantees with respect to the ordering of whether contentious readers or + /// writers will acquire the lock first. + /// + /// # Errors + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(1); + /// + /// let n = lock.read().unwrap(); + /// assert_eq!(*n, 1); + /// + /// assert!(lock.try_write().is_err()); + /// ``` + pub fn try_write(&self) -> TryLockResult> { + let mut poisoned = false; + let mut blocked = None; + + // Write-lock each shard in succession. + for (i, shard) in self.shards.iter().enumerate() { + let guard = match shard.lock.try_write() { + Ok(guard) => guard, + Err(TryLockError::Poisoned(err)) => { + poisoned = true; + err.into_inner() + } + Err(TryLockError::WouldBlock) => { + blocked = Some(i); + break; + } + }; + + // Store the guard into the shard. + unsafe { + let guard: RwLockWriteGuard<'static, ()> = mem::transmute(guard); + let dest: *mut _ = shard.write_guard.get(); + *dest = Some(guard); + } + } + + if let Some(i) = blocked { + // Unlock the shards in reverse order of locking. + for shard in self.shards[0..i].iter().rev() { + unsafe { + let dest: *mut _ = shard.write_guard.get(); + let guard = mem::replace(&mut *dest, None); + drop(guard); + } + } + Err(TryLockError::WouldBlock) + } else if poisoned { + let guard = ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + }; + Err(TryLockError::Poisoned(PoisonError::new(guard))) + } else { + Ok(ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + }) + } + } + + /// Locks with exclusive write access, blocking the current thread until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which hold the lock. + /// There may be other readers currently inside the lock when this method returns. This method + /// does not provide any guarantees with respect to the ordering of whether contentious readers + /// or writers will acquire the lock first. + /// + /// Returns a guard which will release the exclusive access when dropped. + /// + /// # Errors + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Panics + /// + /// This method might panic when called if the lock is already held by the current thread. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(1); + /// + /// let mut n = lock.write().unwrap(); + /// *n = 2; + /// + /// assert!(lock.try_read().is_err()); + /// ``` + pub fn write(&self) -> LockResult> { + let mut poisoned = false; + + // Write-lock each shard in succession. + for shard in self.shards.iter() { + let guard = match shard.lock.write() { + Ok(guard) => guard, + Err(err) => { + poisoned = true; + err.into_inner() + } + }; + + // Store the guard into the shard. + unsafe { + let guard: RwLockWriteGuard<'_, ()> = guard; + let guard: RwLockWriteGuard<'static, ()> = mem::transmute(guard); + let dest: *mut _ = shard.write_guard.get(); + *dest = Some(guard); + } + } + + if poisoned { + Err(PoisonError::new(ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + })) + } else { + Ok(ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + }) + } + } +} + +impl fmt::Debug for ShardedLock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.try_read() { + Ok(guard) => f + .debug_struct("ShardedLock") + .field("data", &&*guard) + .finish(), + Err(TryLockError::Poisoned(err)) => f + .debug_struct("ShardedLock") + .field("data", &&**err.get_ref()) + .finish(), + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("") + } + } + f.debug_struct("ShardedLock") + .field("data", &LockedPlaceholder) + .finish() + } + } + } +} + +impl Default for ShardedLock { + fn default() -> ShardedLock { + ShardedLock::new(Default::default()) + } +} + +impl From for ShardedLock { + fn from(t: T) -> Self { + ShardedLock::new(t) + } +} + +/// A guard used to release the shared read access of a [`ShardedLock`] when dropped. +pub struct ShardedLockReadGuard<'a, T: ?Sized> { + lock: &'a ShardedLock, + _guard: RwLockReadGuard<'a, ()>, + _marker: PhantomData>, +} + +unsafe impl Sync for ShardedLockReadGuard<'_, T> {} + +impl Deref for ShardedLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl fmt::Debug for ShardedLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ShardedLockReadGuard") + .field("lock", &self.lock) + .finish() + } +} + +impl fmt::Display for ShardedLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +/// A guard used to release the exclusive write access of a [`ShardedLock`] when dropped. +pub struct ShardedLockWriteGuard<'a, T: ?Sized> { + lock: &'a ShardedLock, + _marker: PhantomData>, +} + +unsafe impl Sync for ShardedLockWriteGuard<'_, T> {} + +impl Drop for ShardedLockWriteGuard<'_, T> { + fn drop(&mut self) { + // Unlock the shards in reverse order of locking. + for shard in self.lock.shards.iter().rev() { + unsafe { + let dest: *mut _ = shard.write_guard.get(); + let guard = mem::replace(&mut *dest, None); + drop(guard); + } + } + } +} + +impl fmt::Debug for ShardedLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ShardedLockWriteGuard") + .field("lock", &self.lock) + .finish() + } +} + +impl fmt::Display for ShardedLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl Deref for ShardedLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl DerefMut for ShardedLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.lock.value.get() } + } +} + +/// Returns a `usize` that identifies the current thread. +/// +/// Each thread is associated with an 'index'. While there are no particular guarantees, indices +/// usually tend to be consecutive numbers between 0 and the number of running threads. +/// +/// Since this function accesses TLS, `None` might be returned if the current thread's TLS is +/// tearing down. +#[inline] +fn current_index() -> Option { + REGISTRATION.try_with(|reg| reg.index).ok() +} + +/// The global registry keeping track of registered threads and indices. +struct ThreadIndices { + /// Mapping from `ThreadId` to thread index. + mapping: HashMap, + + /// A list of free indices. + free_list: Vec, + + /// The next index to allocate if the free list is empty. + next_index: usize, +} + +lazy_static! { + static ref THREAD_INDICES: Mutex = Mutex::new(ThreadIndices { + mapping: HashMap::new(), + free_list: Vec::new(), + next_index: 0, + }); +} + +/// A registration of a thread with an index. +/// +/// When dropped, unregisters the thread and frees the reserved index. +struct Registration { + index: usize, + thread_id: ThreadId, +} + +impl Drop for Registration { + fn drop(&mut self) { + let mut indices = THREAD_INDICES.lock().unwrap(); + indices.mapping.remove(&self.thread_id); + indices.free_list.push(self.index); + } +} + +thread_local! { + static REGISTRATION: Registration = { + let thread_id = thread::current().id(); + let mut indices = THREAD_INDICES.lock().unwrap(); + + let index = match indices.free_list.pop() { + Some(i) => i, + None => { + let i = indices.next_index; + indices.next_index += 1; + i + } + }; + indices.mapping.insert(thread_id, index); + + Registration { + index, + thread_id, + } + }; +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/wait_group.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/wait_group.rs new file mode 100644 index 0000000..cd7af12 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/sync/wait_group.rs @@ -0,0 +1,146 @@ +// Necessary for using `Mutex` for conditional variables +#![allow(clippy::mutex_atomic)] + +use std::fmt; +use std::sync::{Arc, Condvar, Mutex}; + +/// Enables threads to synchronize the beginning or end of some computation. +/// +/// # Wait groups vs barriers +/// +/// `WaitGroup` is very similar to [`Barrier`], but there are a few differences: +/// +/// * [`Barrier`] needs to know the number of threads at construction, while `WaitGroup` is cloned to +/// register more threads. +/// +/// * A [`Barrier`] can be reused even after all threads have synchronized, while a `WaitGroup` +/// synchronizes threads only once. +/// +/// * All threads wait for others to reach the [`Barrier`]. With `WaitGroup`, each thread can choose +/// to either wait for other threads or to continue without blocking. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::sync::WaitGroup; +/// use std::thread; +/// +/// // Create a new wait group. +/// let wg = WaitGroup::new(); +/// +/// for _ in 0..4 { +/// // Create another reference to the wait group. +/// let wg = wg.clone(); +/// +/// thread::spawn(move || { +/// // Do some work. +/// +/// // Drop the reference to the wait group. +/// drop(wg); +/// }); +/// } +/// +/// // Block until all threads have finished their work. +/// wg.wait(); +/// ``` +/// +/// [`Barrier`]: std::sync::Barrier +pub struct WaitGroup { + inner: Arc, +} + +/// Inner state of a `WaitGroup`. +struct Inner { + cvar: Condvar, + count: Mutex, +} + +impl Default for WaitGroup { + fn default() -> Self { + Self { + inner: Arc::new(Inner { + cvar: Condvar::new(), + count: Mutex::new(1), + }), + } + } +} + +impl WaitGroup { + /// Creates a new wait group and returns the single reference to it. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::WaitGroup; + /// + /// let wg = WaitGroup::new(); + /// ``` + pub fn new() -> Self { + Self::default() + } + + /// Drops this reference and waits until all other references are dropped. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::WaitGroup; + /// use std::thread; + /// + /// let wg = WaitGroup::new(); + /// + /// thread::spawn({ + /// let wg = wg.clone(); + /// move || { + /// // Block until both threads have reached `wait()`. + /// wg.wait(); + /// } + /// }); + /// + /// // Block until both threads have reached `wait()`. + /// wg.wait(); + /// ``` + pub fn wait(self) { + if *self.inner.count.lock().unwrap() == 1 { + return; + } + + let inner = self.inner.clone(); + drop(self); + + let mut count = inner.count.lock().unwrap(); + while *count > 0 { + count = inner.cvar.wait(count).unwrap(); + } + } +} + +impl Drop for WaitGroup { + fn drop(&mut self) { + let mut count = self.inner.count.lock().unwrap(); + *count -= 1; + + if *count == 0 { + self.inner.cvar.notify_all(); + } + } +} + +impl Clone for WaitGroup { + fn clone(&self) -> WaitGroup { + let mut count = self.inner.count.lock().unwrap(); + *count += 1; + + WaitGroup { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for WaitGroup { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let count: &usize = &*self.inner.count.lock().unwrap(); + f.debug_struct("WaitGroup").field("count", count).finish() + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/thread.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/thread.rs new file mode 100644 index 0000000..ab91be7 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/src/thread.rs @@ -0,0 +1,588 @@ +//! Threads that can borrow variables from the stack. +//! +//! Create a scope when spawned threads need to access variables on the stack: +//! +//! ``` +//! use crossbeam_utils::thread; +//! +//! let people = vec![ +//! "Alice".to_string(), +//! "Bob".to_string(), +//! "Carol".to_string(), +//! ]; +//! +//! thread::scope(|s| { +//! for person in &people { +//! s.spawn(move |_| { +//! println!("Hello, {}!", person); +//! }); +//! } +//! }).unwrap(); +//! ``` +//! +//! # Why scoped threads? +//! +//! Suppose we wanted to re-write the previous example using plain threads: +//! +//! ```compile_fail,E0597 +//! use std::thread; +//! +//! let people = vec![ +//! "Alice".to_string(), +//! "Bob".to_string(), +//! "Carol".to_string(), +//! ]; +//! +//! let mut threads = Vec::new(); +//! +//! for person in &people { +//! threads.push(thread::spawn(move || { +//! println!("Hello, {}!", person); +//! })); +//! } +//! +//! for thread in threads { +//! thread.join().unwrap(); +//! } +//! ``` +//! +//! This doesn't work because the borrow checker complains about `people` not living long enough: +//! +//! ```text +//! error[E0597]: `people` does not live long enough +//! --> src/main.rs:12:20 +//! | +//! 12 | for person in &people { +//! | ^^^^^^ borrowed value does not live long enough +//! ... +//! 21 | } +//! | - borrowed value only lives until here +//! | +//! = note: borrowed value must be valid for the static lifetime... +//! ``` +//! +//! The problem here is that spawned threads are not allowed to borrow variables on stack because +//! the compiler cannot prove they will be joined before `people` is destroyed. +//! +//! Scoped threads are a mechanism to guarantee to the compiler that spawned threads will be joined +//! before the scope ends. +//! +//! # How scoped threads work +//! +//! If a variable is borrowed by a thread, the thread must complete before the variable is +//! destroyed. Threads spawned using [`std::thread::spawn`] can only borrow variables with the +//! `'static` lifetime because the borrow checker cannot be sure when the thread will complete. +//! +//! A scope creates a clear boundary between variables outside the scope and threads inside the +//! scope. Whenever a scope spawns a thread, it promises to join the thread before the scope ends. +//! This way we guarantee to the borrow checker that scoped threads only live within the scope and +//! can safely access variables outside it. +//! +//! # Nesting scoped threads +//! +//! Sometimes scoped threads need to spawn more threads within the same scope. This is a little +//! tricky because argument `s` lives *inside* the invocation of `thread::scope()` and as such +//! cannot be borrowed by scoped threads: +//! +//! ```compile_fail,E0373,E0521 +//! use crossbeam_utils::thread; +//! +//! thread::scope(|s| { +//! s.spawn(|_| { +//! // Not going to compile because we're trying to borrow `s`, +//! // which lives *inside* the scope! :( +//! s.spawn(|_| println!("nested thread")); +//! }); +//! }); +//! ``` +//! +//! Fortunately, there is a solution. Every scoped thread is passed a reference to its scope as an +//! argument, which can be used for spawning nested threads: +//! +//! ``` +//! use crossbeam_utils::thread; +//! +//! thread::scope(|s| { +//! // Note the `|s|` here. +//! s.spawn(|s| { +//! // Yay, this works because we're using a fresh argument `s`! :) +//! s.spawn(|_| println!("nested thread")); +//! }); +//! }).unwrap(); +//! ``` +//! +//! [`std::thread::spawn`]: std::thread::spawn + +use std::fmt; +use std::io; +use std::marker::PhantomData; +use std::mem; +use std::panic; +use std::sync::{Arc, Mutex}; +use std::thread; + +use crate::sync::WaitGroup; +use cfg_if::cfg_if; + +type SharedVec = Arc>>; +type SharedOption = Arc>>; + +/// Creates a new scope for spawning threads. +/// +/// All child threads that haven't been manually joined will be automatically joined just before +/// this function invocation ends. If all joined threads have successfully completed, `Ok` is +/// returned with the return value of `f`. If any of the joined threads has panicked, an `Err` is +/// returned containing errors from panicked threads. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::thread; +/// +/// let var = vec![1, 2, 3]; +/// +/// thread::scope(|s| { +/// s.spawn(|_| { +/// println!("A child thread borrowing `var`: {:?}", var); +/// }); +/// }).unwrap(); +/// ``` +pub fn scope<'env, F, R>(f: F) -> thread::Result +where + F: FnOnce(&Scope<'env>) -> R, +{ + let wg = WaitGroup::new(); + let scope = Scope::<'env> { + handles: SharedVec::default(), + wait_group: wg.clone(), + _marker: PhantomData, + }; + + // Execute the scoped function, but catch any panics. + let result = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&scope))); + + // Wait until all nested scopes are dropped. + drop(scope.wait_group); + wg.wait(); + + // Join all remaining spawned threads. + let panics: Vec<_> = scope + .handles + .lock() + .unwrap() + // Filter handles that haven't been joined, join them, and collect errors. + .drain(..) + .filter_map(|handle| handle.lock().unwrap().take()) + .filter_map(|handle| handle.join().err()) + .collect(); + + // If `f` has panicked, resume unwinding. + // If any of the child threads have panicked, return the panic errors. + // Otherwise, everything is OK and return the result of `f`. + match result { + Err(err) => panic::resume_unwind(err), + Ok(res) => { + if panics.is_empty() { + Ok(res) + } else { + Err(Box::new(panics)) + } + } + } +} + +/// A scope for spawning threads. +pub struct Scope<'env> { + /// The list of the thread join handles. + handles: SharedVec>>, + + /// Used to wait until all subscopes all dropped. + wait_group: WaitGroup, + + /// Borrows data with invariant lifetime `'env`. + _marker: PhantomData<&'env mut &'env ()>, +} + +unsafe impl Sync for Scope<'_> {} + +impl<'env> Scope<'env> { + /// Spawns a scoped thread. + /// + /// This method is similar to the [`spawn`] function in Rust's standard library. The difference + /// is that this thread is scoped, meaning it's guaranteed to terminate before the scope exits, + /// allowing it to reference variables outside the scope. + /// + /// The scoped thread is passed a reference to this scope as an argument, which can be used for + /// spawning nested threads. + /// + /// The returned [handle](ScopedJoinHandle) can be used to manually + /// [join](ScopedJoinHandle::join) the thread before the scope exits. + /// + /// This will create a thread using default parameters of [`ScopedThreadBuilder`], if you want to specify the + /// stack size or the name of the thread, use this API instead. + /// + /// [`spawn`]: std::thread::spawn + /// + /// # Panics + /// + /// Panics if the OS fails to create a thread; use [`ScopedThreadBuilder::spawn`] + /// to recover from such errors. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle = s.spawn(|_| { + /// println!("A child thread is running"); + /// 42 + /// }); + /// + /// // Join the thread and retrieve its result. + /// let res = handle.join().unwrap(); + /// assert_eq!(res, 42); + /// }).unwrap(); + /// ``` + pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> + where + F: FnOnce(&Scope<'env>) -> T, + F: Send + 'env, + T: Send + 'env, + { + self.builder() + .spawn(f) + .expect("failed to spawn scoped thread") + } + + /// Creates a builder that can configure a thread before spawning. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// s.builder() + /// .spawn(|_| println!("A child thread is running")) + /// .unwrap(); + /// }).unwrap(); + /// ``` + pub fn builder<'scope>(&'scope self) -> ScopedThreadBuilder<'scope, 'env> { + ScopedThreadBuilder { + scope: self, + builder: thread::Builder::new(), + } + } +} + +impl fmt::Debug for Scope<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("Scope { .. }") + } +} + +/// Configures the properties of a new thread. +/// +/// The two configurable properties are: +/// +/// - [`name`]: Specifies an [associated name for the thread][naming-threads]. +/// - [`stack_size`]: Specifies the [desired stack size for the thread][stack-size]. +/// +/// The [`spawn`] method will take ownership of the builder and return an [`io::Result`] of the +/// thread handle with the given configuration. +/// +/// The [`Scope::spawn`] method uses a builder with default configuration and unwraps its return +/// value. You may want to use this builder when you want to recover from a failure to launch a +/// thread. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::thread; +/// +/// thread::scope(|s| { +/// s.builder() +/// .spawn(|_| println!("Running a child thread")) +/// .unwrap(); +/// }).unwrap(); +/// ``` +/// +/// [`name`]: ScopedThreadBuilder::name +/// [`stack_size`]: ScopedThreadBuilder::stack_size +/// [`spawn`]: ScopedThreadBuilder::spawn +/// [`io::Result`]: std::io::Result +/// [naming-threads]: std::thread#naming-threads +/// [stack-size]: std::thread#stack-size +#[derive(Debug)] +pub struct ScopedThreadBuilder<'scope, 'env> { + scope: &'scope Scope<'env>, + builder: thread::Builder, +} + +impl<'scope, 'env> ScopedThreadBuilder<'scope, 'env> { + /// Sets the name for the new thread. + /// + /// The name must not contain null bytes (`\0`). + /// + /// For more information about named threads, see [here][naming-threads]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// use std::thread::current; + /// + /// thread::scope(|s| { + /// s.builder() + /// .name("my thread".to_string()) + /// .spawn(|_| assert_eq!(current().name(), Some("my thread"))) + /// .unwrap(); + /// }).unwrap(); + /// ``` + /// + /// [naming-threads]: std::thread#naming-threads + pub fn name(mut self, name: String) -> ScopedThreadBuilder<'scope, 'env> { + self.builder = self.builder.name(name); + self + } + + /// Sets the size of the stack for the new thread. + /// + /// The stack size is measured in bytes. + /// + /// For more information about the stack size for threads, see [here][stack-size]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// s.builder() + /// .stack_size(32 * 1024) + /// .spawn(|_| println!("Running a child thread")) + /// .unwrap(); + /// }).unwrap(); + /// ``` + /// + /// [stack-size]: std::thread#stack-size + pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'scope, 'env> { + self.builder = self.builder.stack_size(size); + self + } + + /// Spawns a scoped thread with this configuration. + /// + /// The scoped thread is passed a reference to this scope as an argument, which can be used for + /// spawning nested threads. + /// + /// The returned handle can be used to manually join the thread before the scope exits. + /// + /// # Errors + /// + /// Unlike the [`Scope::spawn`] method, this method yields an + /// [`io::Result`] to capture any failure to create the thread at + /// the OS level. + /// + /// [`io::Result`]: std::io::Result + /// + /// # Panics + /// + /// Panics if a thread name was set and it contained null bytes. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle = s.builder() + /// .spawn(|_| { + /// println!("A child thread is running"); + /// 42 + /// }) + /// .unwrap(); + /// + /// // Join the thread and retrieve its result. + /// let res = handle.join().unwrap(); + /// assert_eq!(res, 42); + /// }).unwrap(); + /// ``` + pub fn spawn(self, f: F) -> io::Result> + where + F: FnOnce(&Scope<'env>) -> T, + F: Send + 'env, + T: Send + 'env, + { + // The result of `f` will be stored here. + let result = SharedOption::default(); + + // Spawn the thread and grab its join handle and thread handle. + let (handle, thread) = { + let result = Arc::clone(&result); + + // A clone of the scope that will be moved into the new thread. + let scope = Scope::<'env> { + handles: Arc::clone(&self.scope.handles), + wait_group: self.scope.wait_group.clone(), + _marker: PhantomData, + }; + + // Spawn the thread. + let handle = { + let closure = move || { + // Make sure the scope is inside the closure with the proper `'env` lifetime. + let scope: Scope<'env> = scope; + + // Run the closure. + let res = f(&scope); + + // Store the result if the closure didn't panic. + *result.lock().unwrap() = Some(res); + }; + + // Allocate `closure` on the heap and erase the `'env` bound. + let closure: Box = Box::new(closure); + let closure: Box = + unsafe { mem::transmute(closure) }; + + // Finally, spawn the closure. + self.builder.spawn(move || closure())? + }; + + let thread = handle.thread().clone(); + let handle = Arc::new(Mutex::new(Some(handle))); + (handle, thread) + }; + + // Add the handle to the shared list of join handles. + self.scope.handles.lock().unwrap().push(Arc::clone(&handle)); + + Ok(ScopedJoinHandle { + handle, + result, + thread, + _marker: PhantomData, + }) + } +} + +unsafe impl Send for ScopedJoinHandle<'_, T> {} +unsafe impl Sync for ScopedJoinHandle<'_, T> {} + +/// A handle that can be used to join its scoped thread. +/// +/// This struct is created by the [`Scope::spawn`] method and the +/// [`ScopedThreadBuilder::spawn`] method. +pub struct ScopedJoinHandle<'scope, T> { + /// A join handle to the spawned thread. + handle: SharedOption>, + + /// Holds the result of the inner closure. + result: SharedOption, + + /// A handle to the the spawned thread. + thread: thread::Thread, + + /// Borrows the parent scope with lifetime `'scope`. + _marker: PhantomData<&'scope ()>, +} + +impl ScopedJoinHandle<'_, T> { + /// Waits for the thread to finish and returns its result. + /// + /// If the child thread panics, an error is returned. + /// + /// # Panics + /// + /// This function may panic on some platforms if a thread attempts to join itself or otherwise + /// may create a deadlock with joining threads. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle1 = s.spawn(|_| println!("I'm a happy thread :)")); + /// let handle2 = s.spawn(|_| panic!("I'm a sad thread :(")); + /// + /// // Join the first thread and verify that it succeeded. + /// let res = handle1.join(); + /// assert!(res.is_ok()); + /// + /// // Join the second thread and verify that it panicked. + /// let res = handle2.join(); + /// assert!(res.is_err()); + /// }).unwrap(); + /// ``` + pub fn join(self) -> thread::Result { + // Take out the handle. The handle will surely be available because the root scope waits + // for nested scopes before joining remaining threads. + let handle = self.handle.lock().unwrap().take().unwrap(); + + // Join the thread and then take the result out of its inner closure. + handle + .join() + .map(|()| self.result.lock().unwrap().take().unwrap()) + } + + /// Returns a handle to the underlying thread. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle = s.spawn(|_| println!("A child thread is running")); + /// println!("The child thread ID: {:?}", handle.thread().id()); + /// }).unwrap(); + /// ``` + pub fn thread(&self) -> &thread::Thread { + &self.thread + } +} + +cfg_if! { + if #[cfg(unix)] { + use std::os::unix::thread::{JoinHandleExt, RawPthread}; + + impl JoinHandleExt for ScopedJoinHandle<'_, T> { + fn as_pthread_t(&self) -> RawPthread { + // Borrow the handle. The handle will surely be available because the root scope waits + // for nested scopes before joining remaining threads. + let handle = self.handle.lock().unwrap(); + handle.as_ref().unwrap().as_pthread_t() + } + fn into_pthread_t(self) -> RawPthread { + self.as_pthread_t() + } + } + } else if #[cfg(windows)] { + use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle}; + + impl AsRawHandle for ScopedJoinHandle<'_, T> { + fn as_raw_handle(&self) -> RawHandle { + // Borrow the handle. The handle will surely be available because the root scope waits + // for nested scopes before joining remaining threads. + let handle = self.handle.lock().unwrap(); + handle.as_ref().unwrap().as_raw_handle() + } + } + + #[cfg(windows)] + impl IntoRawHandle for ScopedJoinHandle<'_, T> { + fn into_raw_handle(self) -> RawHandle { + self.as_raw_handle() + } + } + } +} + +impl fmt::Debug for ScopedJoinHandle<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("ScopedJoinHandle { .. }") + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/atomic_cell.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/atomic_cell.rs new file mode 100644 index 0000000..3d91d81 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/atomic_cell.rs @@ -0,0 +1,236 @@ +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +use crossbeam_utils::atomic::AtomicCell; + +#[test] +fn is_lock_free() { + struct UsizeWrap(usize); + struct U8Wrap(bool); + struct I16Wrap(i16); + + assert_eq!(AtomicCell::::is_lock_free(), true); + assert_eq!(AtomicCell::::is_lock_free(), true); + assert_eq!(AtomicCell::::is_lock_free(), true); + + assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u8)); + assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u8)); + assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u8)); + + assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u16)); + + assert_eq!(AtomicCell::::is_lock_free(), cfg!(has_atomic_u128)); +} + +#[test] +fn const_is_lock_free() { + const _U: bool = AtomicCell::::is_lock_free(); + const _I: bool = AtomicCell::::is_lock_free(); +} + +#[test] +fn drops_unit() { + static CNT: AtomicUsize = AtomicUsize::new(0); + CNT.store(0, SeqCst); + + #[derive(Debug, PartialEq, Eq)] + struct Foo(); + + impl Foo { + fn new() -> Foo { + CNT.fetch_add(1, SeqCst); + Foo() + } + } + + impl Drop for Foo { + fn drop(&mut self) { + CNT.fetch_sub(1, SeqCst); + } + } + + impl Default for Foo { + fn default() -> Foo { + Foo::new() + } + } + + let a = AtomicCell::new(Foo::new()); + + assert_eq!(a.swap(Foo::new()), Foo::new()); + assert_eq!(CNT.load(SeqCst), 1); + + a.store(Foo::new()); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new()); + assert_eq!(CNT.load(SeqCst), 1); + + drop(a); + assert_eq!(CNT.load(SeqCst), 0); +} + +#[test] +fn drops_u8() { + static CNT: AtomicUsize = AtomicUsize::new(0); + CNT.store(0, SeqCst); + + #[derive(Debug, PartialEq, Eq)] + struct Foo(u8); + + impl Foo { + fn new(val: u8) -> Foo { + CNT.fetch_add(1, SeqCst); + Foo(val) + } + } + + impl Drop for Foo { + fn drop(&mut self) { + CNT.fetch_sub(1, SeqCst); + } + } + + impl Default for Foo { + fn default() -> Foo { + Foo::new(0) + } + } + + let a = AtomicCell::new(Foo::new(5)); + + assert_eq!(a.swap(Foo::new(6)), Foo::new(5)); + assert_eq!(a.swap(Foo::new(1)), Foo::new(6)); + assert_eq!(CNT.load(SeqCst), 1); + + a.store(Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(0)); + assert_eq!(CNT.load(SeqCst), 1); + + drop(a); + assert_eq!(CNT.load(SeqCst), 0); +} + +#[test] +fn drops_usize() { + static CNT: AtomicUsize = AtomicUsize::new(0); + CNT.store(0, SeqCst); + + #[derive(Debug, PartialEq, Eq)] + struct Foo(usize); + + impl Foo { + fn new(val: usize) -> Foo { + CNT.fetch_add(1, SeqCst); + Foo(val) + } + } + + impl Drop for Foo { + fn drop(&mut self) { + CNT.fetch_sub(1, SeqCst); + } + } + + impl Default for Foo { + fn default() -> Foo { + Foo::new(0) + } + } + + let a = AtomicCell::new(Foo::new(5)); + + assert_eq!(a.swap(Foo::new(6)), Foo::new(5)); + assert_eq!(a.swap(Foo::new(1)), Foo::new(6)); + assert_eq!(CNT.load(SeqCst), 1); + + a.store(Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(0)); + assert_eq!(CNT.load(SeqCst), 1); + + drop(a); + assert_eq!(CNT.load(SeqCst), 0); +} + +#[test] +fn modular_u8() { + #[derive(Clone, Copy, Eq, Debug, Default)] + struct Foo(u8); + + impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.0 % 5 == other.0 % 5 + } + } + + let a = AtomicCell::new(Foo(1)); + + assert_eq!(a.load(), Foo(1)); + assert_eq!(a.swap(Foo(2)), Foo(11)); + assert_eq!(a.load(), Foo(52)); + + a.store(Foo(0)); + assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100))); + assert_eq!(a.load().0, 5); + assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100))); + assert_eq!(a.load().0, 15); +} + +#[test] +fn modular_usize() { + #[derive(Clone, Copy, Eq, Debug, Default)] + struct Foo(usize); + + impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.0 % 5 == other.0 % 5 + } + } + + let a = AtomicCell::new(Foo(1)); + + assert_eq!(a.load(), Foo(1)); + assert_eq!(a.swap(Foo(2)), Foo(11)); + assert_eq!(a.load(), Foo(52)); + + a.store(Foo(0)); + assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100))); + assert_eq!(a.load().0, 5); + assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100))); + assert_eq!(a.load().0, 15); +} + +#[test] +fn garbage_padding() { + #[derive(Copy, Clone, Eq, PartialEq)] + struct Object { + a: i64, + b: i32, + } + + let cell = AtomicCell::new(Object { a: 0, b: 0 }); + let _garbage = [0xfe, 0xfe, 0xfe, 0xfe, 0xfe]; // Needed + let next = Object { a: 0, b: 0 }; + + let prev = cell.load(); + assert!(cell.compare_exchange(prev, next).is_ok()); + println!(); +} + +#[test] +fn const_atomic_cell_new() { + static CELL: AtomicCell = AtomicCell::new(0); + + CELL.store(1); + assert_eq!(CELL.load(), 1); +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/cache_padded.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/cache_padded.rs new file mode 100644 index 0000000..be90cbe --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/cache_padded.rs @@ -0,0 +1,110 @@ +use std::cell::Cell; +use std::mem; + +use crossbeam_utils::CachePadded; + +#[test] +fn default() { + let x: CachePadded = Default::default(); + assert_eq!(*x, 0); +} + +#[test] +fn store_u64() { + let x: CachePadded = CachePadded::new(17); + assert_eq!(*x, 17); +} + +#[test] +fn store_pair() { + let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37)); + assert_eq!(x.0, 17); + assert_eq!(x.1, 37); +} + +#[test] +fn distance() { + let arr = [CachePadded::new(17u8), CachePadded::new(37u8)]; + let a = &*arr[0] as *const u8; + let b = &*arr[1] as *const u8; + assert!(unsafe { a.offset(64) } <= b); +} + +#[test] +fn different_sizes() { + CachePadded::new(17u8); + CachePadded::new(17u16); + CachePadded::new(17u32); + CachePadded::new([17u64; 0]); + CachePadded::new([17u64; 1]); + CachePadded::new([17u64; 2]); + CachePadded::new([17u64; 3]); + CachePadded::new([17u64; 4]); + CachePadded::new([17u64; 5]); + CachePadded::new([17u64; 6]); + CachePadded::new([17u64; 7]); + CachePadded::new([17u64; 8]); +} + +#[test] +fn large() { + let a = [17u64; 9]; + let b = CachePadded::new(a); + assert!(mem::size_of_val(&a) <= mem::size_of_val(&b)); +} + +#[test] +fn debug() { + assert_eq!( + format!("{:?}", CachePadded::new(17u64)), + "CachePadded { value: 17 }" + ); +} + +#[test] +fn drops() { + let count = Cell::new(0); + + struct Foo<'a>(&'a Cell); + + impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + let a = CachePadded::new(Foo(&count)); + let b = CachePadded::new(Foo(&count)); + + assert_eq!(count.get(), 0); + drop(a); + assert_eq!(count.get(), 1); + drop(b); + assert_eq!(count.get(), 2); +} + +#[test] +fn clone() { + let a = CachePadded::new(17); + let b = a.clone(); + assert_eq!(*a, *b); +} + +#[test] +fn runs_custom_clone() { + let count = Cell::new(0); + + struct Foo<'a>(&'a Cell); + + impl<'a> Clone for Foo<'a> { + fn clone(&self) -> Foo<'a> { + self.0.set(self.0.get() + 1); + Foo::<'a>(self.0) + } + } + + let a = CachePadded::new(Foo(&count)); + let _ = a.clone(); + + assert_eq!(count.get(), 1); +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/parker.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/parker.rs new file mode 100644 index 0000000..f657eb1 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/parker.rs @@ -0,0 +1,41 @@ +use std::thread::sleep; +use std::time::Duration; +use std::u32; + +use crossbeam_utils::sync::Parker; +use crossbeam_utils::thread; + +#[test] +fn park_timeout_unpark_before() { + let p = Parker::new(); + for _ in 0..10 { + p.unparker().unpark(); + p.park_timeout(Duration::from_millis(u32::MAX as u64)); + } +} + +#[test] +fn park_timeout_unpark_not_called() { + let p = Parker::new(); + for _ in 0..10 { + p.park_timeout(Duration::from_millis(10)); + } +} + +#[test] +fn park_timeout_unpark_called_other_thread() { + for _ in 0..10 { + let p = Parker::new(); + let u = p.unparker().clone(); + + thread::scope(|scope| { + scope.spawn(move |_| { + sleep(Duration::from_millis(50)); + u.unpark(); + }); + + p.park_timeout(Duration::from_millis(u32::MAX as u64)); + }) + .unwrap(); + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/sharded_lock.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/sharded_lock.rs new file mode 100644 index 0000000..73bd489 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/sharded_lock.rs @@ -0,0 +1,252 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::mpsc::channel; +use std::sync::{Arc, TryLockError}; +use std::thread; + +use crossbeam_utils::sync::ShardedLock; +use rand::Rng; + +#[derive(Eq, PartialEq, Debug)] +struct NonCopy(i32); + +#[test] +fn smoke() { + let l = ShardedLock::new(()); + drop(l.read().unwrap()); + drop(l.write().unwrap()); + drop((l.read().unwrap(), l.read().unwrap())); + drop(l.write().unwrap()); +} + +#[test] +fn frob() { + const N: u32 = 10; + const M: usize = 1000; + + let r = Arc::new(ShardedLock::new(())); + + let (tx, rx) = channel::<()>(); + for _ in 0..N { + let tx = tx.clone(); + let r = r.clone(); + thread::spawn(move || { + let mut rng = rand::thread_rng(); + for _ in 0..M { + if rng.gen_bool(1.0 / (N as f64)) { + drop(r.write().unwrap()); + } else { + drop(r.read().unwrap()); + } + } + drop(tx); + }); + } + drop(tx); + let _ = rx.recv(); +} + +#[test] +fn arc_poison_wr() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.read().is_err()); +} + +#[test] +fn arc_poison_ww() { + let arc = Arc::new(ShardedLock::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +fn arc_no_poison_rr() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} +#[test] +fn arc_no_poison_sl() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!() + }) + .join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +fn arc() { + let arc = Arc::new(ShardedLock::new(0)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + thread::spawn(move || { + let mut lock = arc2.write().unwrap(); + for _ in 0..10 { + let tmp = *lock; + *lock = -1; + thread::yield_now(); + *lock = tmp + 1; + } + tx.send(()).unwrap(); + }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in 0..5 { + let arc3 = arc.clone(); + children.push(thread::spawn(move || { + let lock = arc3.read().unwrap(); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children { + assert!(r.join().is_ok()); + } + + // Wait for writer to finish + rx.recv().unwrap(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 10); +} + +#[test] +fn arc_access_in_unwind() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = self.i.write().unwrap(); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 2); +} + +#[test] +fn unsized_type() { + let sl: &ShardedLock<[i32]> = &ShardedLock::new([1, 2, 3]); + { + let b = &mut *sl.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*sl.read().unwrap(), comp); +} + +#[test] +fn try_write() { + let lock = ShardedLock::new(0isize); + let read_guard = lock.read().unwrap(); + + let write_result = lock.try_write(); + match write_result { + Err(TryLockError::WouldBlock) => (), + Ok(_) => assert!( + false, + "try_write should not succeed while read_guard is in scope" + ), + Err(_) => assert!(false, "unexpected error"), + } + + drop(read_guard); +} + +#[test] +fn test_into_inner() { + let m = ShardedLock::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); +} + +#[test] +fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = ShardedLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); +} + +#[test] +fn test_into_inner_poison() { + let m = Arc::new(ShardedLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison ShardedLock"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned ShardedLock is Ok: {:?}", x), + } +} + +#[test] +fn test_get_mut() { + let mut m = ShardedLock::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); +} + +#[test] +fn test_get_mut_poison() { + let m = Arc::new(ShardedLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison ShardedLock"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned ShardedLock is Ok: {:?}", x), + } +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/thread.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/thread.rs new file mode 100644 index 0000000..0dfad90 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/thread.rs @@ -0,0 +1,215 @@ +use std::any::Any; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::sleep; +use std::time::Duration; + +use crossbeam_utils::thread; + +const THREADS: usize = 10; +const SMALL_STACK_SIZE: usize = 20; + +#[test] +fn join() { + let counter = AtomicUsize::new(0); + thread::scope(|scope| { + let handle = scope.spawn(|_| { + counter.store(1, Ordering::Relaxed); + }); + assert!(handle.join().is_ok()); + + let panic_handle = scope.spawn(|_| { + panic!("\"My honey is running out!\", said Pooh."); + }); + assert!(panic_handle.join().is_err()); + }) + .unwrap(); + + // There should be sufficient synchronization. + assert_eq!(1, counter.load(Ordering::Relaxed)); +} + +#[test] +fn counter() { + let counter = AtomicUsize::new(0); + thread::scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }) + .unwrap(); + + assert_eq!(THREADS, counter.load(Ordering::Relaxed)); +} + +#[test] +fn counter_builder() { + let counter = AtomicUsize::new(0); + thread::scope(|scope| { + for i in 0..THREADS { + scope + .builder() + .name(format!("child-{}", i)) + .stack_size(SMALL_STACK_SIZE) + .spawn(|_| { + counter.fetch_add(1, Ordering::Relaxed); + }) + .unwrap(); + } + }) + .unwrap(); + + assert_eq!(THREADS, counter.load(Ordering::Relaxed)); +} + +#[test] +fn counter_panic() { + let counter = AtomicUsize::new(0); + let result = thread::scope(|scope| { + scope.spawn(|_| { + panic!("\"My honey is running out!\", said Pooh."); + }); + sleep(Duration::from_millis(100)); + + for _ in 0..THREADS { + scope.spawn(|_| { + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + + assert_eq!(THREADS, counter.load(Ordering::Relaxed)); + assert!(result.is_err()); +} + +#[test] +fn panic_twice() { + let result = thread::scope(|scope| { + scope.spawn(|_| { + sleep(Duration::from_millis(500)); + panic!("thread #1"); + }); + scope.spawn(|_| { + panic!("thread #2"); + }); + }); + + let err = result.unwrap_err(); + let vec = err + .downcast_ref::>>() + .unwrap(); + assert_eq!(2, vec.len()); + + let first = vec[0].downcast_ref::<&str>().unwrap(); + let second = vec[1].downcast_ref::<&str>().unwrap(); + assert_eq!("thread #1", *first); + assert_eq!("thread #2", *second) +} + +#[test] +fn panic_many() { + let result = thread::scope(|scope| { + scope.spawn(|_| panic!("deliberate panic #1")); + scope.spawn(|_| panic!("deliberate panic #2")); + scope.spawn(|_| panic!("deliberate panic #3")); + }); + + let err = result.unwrap_err(); + let vec = err + .downcast_ref::>>() + .unwrap(); + assert_eq!(3, vec.len()); + + for panic in vec.iter() { + let panic = panic.downcast_ref::<&str>().unwrap(); + assert!( + *panic == "deliberate panic #1" + || *panic == "deliberate panic #2" + || *panic == "deliberate panic #3" + ); + } +} + +#[test] +fn nesting() { + let var = "foo".to_string(); + + struct Wrapper<'a> { + var: &'a String, + } + + impl<'a> Wrapper<'a> { + fn recurse(&'a self, scope: &thread::Scope<'a>, depth: usize) { + assert_eq!(self.var, "foo"); + + if depth > 0 { + scope.spawn(move |scope| { + self.recurse(scope, depth - 1); + }); + } + } + } + + let wrapper = Wrapper { var: &var }; + + thread::scope(|scope| { + scope.spawn(|scope| { + scope.spawn(|scope| { + wrapper.recurse(scope, 5); + }); + }); + }) + .unwrap(); +} + +#[test] +fn join_nested() { + thread::scope(|scope| { + scope.spawn(|scope| { + let handle = scope.spawn(|_| 7); + + sleep(Duration::from_millis(200)); + handle.join().unwrap(); + }); + + sleep(Duration::from_millis(100)); + }) + .unwrap(); +} + +#[test] +fn scope_returns_ok() { + let result = thread::scope(|scope| scope.spawn(|_| 1234).join().unwrap()).unwrap(); + assert_eq!(result, 1234); +} + +#[cfg(unix)] +#[test] +fn as_pthread_t() { + use std::os::unix::thread::JoinHandleExt; + thread::scope(|scope| { + let handle = scope.spawn(|_scope| { + sleep(Duration::from_millis(100)); + 42 + }); + let _pthread_t = handle.as_pthread_t(); + handle.join().unwrap(); + }) + .unwrap(); +} + +#[cfg(windows)] +#[test] +fn as_raw_handle() { + use std::os::windows::io::AsRawHandle; + thread::scope(|scope| { + let handle = scope.spawn(|_scope| { + sleep(Duration::from_millis(100)); + 42 + }); + let _raw_handle = handle.as_raw_handle(); + handle.join().unwrap(); + }) + .unwrap(); +} diff --git a/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/wait_group.rs b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/wait_group.rs new file mode 100644 index 0000000..b6c2a24 --- /dev/null +++ b/third_party/cargo/vendor/crossbeam-utils-0.8.1/tests/wait_group.rs @@ -0,0 +1,64 @@ +use std::sync::mpsc; +use std::thread; +use std::time::Duration; + +use crossbeam_utils::sync::WaitGroup; + +const THREADS: usize = 10; + +#[test] +fn wait() { + let wg = WaitGroup::new(); + let (tx, rx) = mpsc::channel(); + + for _ in 0..THREADS { + let wg = wg.clone(); + let tx = tx.clone(); + + thread::spawn(move || { + wg.wait(); + tx.send(()).unwrap(); + }); + } + + thread::sleep(Duration::from_millis(100)); + + // At this point, all spawned threads should be blocked, so we shouldn't get anything from the + // channel. + assert!(rx.try_recv().is_err()); + + wg.wait(); + + // Now, the wait group is cleared and we should receive messages. + for _ in 0..THREADS { + rx.recv().unwrap(); + } +} + +#[test] +fn wait_and_drop() { + let wg = WaitGroup::new(); + let (tx, rx) = mpsc::channel(); + + for _ in 0..THREADS { + let wg = wg.clone(); + let tx = tx.clone(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + tx.send(()).unwrap(); + drop(wg); + }); + } + + // At this point, all spawned threads should be sleeping, so we shouldn't get anything from the + // channel. + assert!(rx.try_recv().is_err()); + + wg.wait(); + + // Now, the wait group is cleared and we should receive messages. + for _ in 0..THREADS { + rx.try_recv().unwrap(); + } +} diff --git a/third_party/cargo/vendor/darling-0.10.2/.cargo-checksum.json b/third_party/cargo/vendor/darling-0.10.2/.cargo-checksum.json new file mode 100644 index 0000000..93554ee --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"ecd47a7e03d29736e441898eb3a31c39955d136d01e07ba89b9a869d020d1c1f","Cargo.lock":"e12abfb6c313993690caa5bd4d822dd70fd8661cd9062a61a7426f011f2320bf","Cargo.toml":"535f9d48e82e04c5c620039d36f9539d6f83b96f941f00731a2946b45bd8d785","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","README.md":"5b591026cb7c3ed964d46779f323a2b45f89aa18d2bc5f63519126cb3b7efed9","examples/automatic_bounds.rs":"2540e6eb0761755737927a0e01d94956a1e9db04db67ae1aba3110415759fac4","examples/consume_fields.rs":"ebf4bd8baf4e54ccaa926f910957183d6a5b1decaa87ab5ebcca6c8d38b6c6b3","examples/fallible_read.rs":"aa9d1e0aaba8f3eb4580e94e133839f7eb77fca61beed254f3d5e0f6d6981f00","examples/supports_struct.rs":"d69124e09d3d6b8e04a3af07a6af96c5df7cbd3d6953a51657b39088cc2c2de7","src/lib.rs":"07da20edb52c4aba30f2b680b28ca96cf995859566b0db3b1d2e0ee967249a18","src/macros_public.rs":"3ed7eb99f309d9cd600d3a09ff4dcf5cc5d787fb49e8e5ead6bb00e31e5e6793","tests/accrue_errors.rs":"f5ac2d8cb0a12284a845d25b9472c4605aa5e8c1cd66a6dd6ad64f1c749b2caf","tests/computed_bound.rs":"2313da96a250b5948ca06bf86cb7158b55a59eba75334aa8ba27a46b28ede6b5","tests/custom_bound.rs":"4dd3e8fd76734d8f262e857773f53a820229ad6e10fe6fbbbe1f636c7da9eab0","tests/defaults.rs":"b544be90d18be26305a757e8468bf8735356889b59c167294d118e32ee7f82ea","tests/enums_newtype.rs":"a09af70072e566bee1f6cad91675f3553c47333e51a0e389ebb47ae82de776a8","tests/enums_struct.rs":"e0097d7f947cf9e4612c9450c55ea5075c7f6fcbbf8cac7176449d92eebc9343","tests/enums_unit.rs":"8c075d5897b60b58cb71d6306e7fdd80851f5a147ae3010ba70ea100007364a3","tests/error.rs":"465f7634fa23f0076c93a9c5fc16ccde16119b874d64c8dabaf275b6b7ae61f2","tests/from_generics.rs":"79230ad21e8482cf6e6ceb0c74303bc0cdf77fbb951f46a6ba1006ecf1248fd5","tests/from_type_param.rs":"7c97745cdcea18a2d6f51e4da7426055a078287bf9f2c93d487057195efa2b30","tests/from_type_param_default.rs":"80787ef6527e7f76c2aac93b1f35a006a9c5e0df8deed61698eaac1127278021","tests/from_variant.rs":"2e804326302a62b979eae963e88f0a2cdb6a21ee9667407c361d178f8c0aadba","tests/generics.rs":"e08aea8a8de8f03e3c243bde650e250defbe340cef3e4c06935b2b3e46d2a376","tests/happy_path.rs":"c32daa68e2becdc2d6204985a19b437cfb49d7f1680e890578f0760dc9749b77","tests/multiple.rs":"0391be49bab07771d7e37d35fe17f6d9bf1aa6dc57e2c0e5c0912ab8e043128f","tests/newtype.rs":"3f029724467abc7a33aaf7b6a1feb7b6898eba578576afff338e73deb9fd2b3b","tests/skip.rs":"604861aa4d1dfdc4e5f38f8261be19b7240c650eb493b64ce0178f54c24a8d2d","tests/split_declaration.rs":"f509390f88549164af9218f1e5b07564b169a4481a20b738432ffb03c517b599","tests/suggestions.rs":"0afb756949be876aaae76974f119be811c783fb134a54978ff0453c537ff3174","tests/supports.rs":"8564709d7e63b124cda91f7e21c890037200e533d0403ffd7eb075403cf58926"},"package":"0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"} \ No newline at end of file diff --git a/third_party/cargo/vendor/darling-0.10.2/BUILD.bazel b/third_party/cargo/vendor/darling-0.10.2/BUILD.bazel new file mode 100644 index 0000000..ab54fa3 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/BUILD.bazel @@ -0,0 +1,107 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT" +]) + +# Generated Targets + +# Unsupported target "automatic_bounds" with type "example" omitted + +# Unsupported target "consume_fields" with type "example" omitted + +# Unsupported target "fallible_read" with type "example" omitted + +# Unsupported target "supports_struct" with type "example" omitted + +rust_library( + name = "darling", + srcs = glob(["**/*.rs"]), + crate_features = [ + "default", + "suggestions", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + proc_macro_deps = [ + "//third_party/cargo/vendor/darling_macro-0.10.2:darling_macro", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.10.2", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/darling_core-0.10.2:darling_core", + ], +) + +# Unsupported target "accrue_errors" with type "test" omitted + +# Unsupported target "computed_bound" with type "test" omitted + +# Unsupported target "custom_bound" with type "test" omitted + +# Unsupported target "defaults" with type "test" omitted + +# Unsupported target "enums_newtype" with type "test" omitted + +# Unsupported target "enums_struct" with type "test" omitted + +# Unsupported target "enums_unit" with type "test" omitted + +# Unsupported target "error" with type "test" omitted + +# Unsupported target "from_generics" with type "test" omitted + +# Unsupported target "from_type_param" with type "test" omitted + +# Unsupported target "from_type_param_default" with type "test" omitted + +# Unsupported target "from_variant" with type "test" omitted + +# Unsupported target "generics" with type "test" omitted + +# Unsupported target "happy_path" with type "test" omitted + +# Unsupported target "multiple" with type "test" omitted + +# Unsupported target "newtype" with type "test" omitted + +# Unsupported target "skip" with type "test" omitted + +# Unsupported target "split_declaration" with type "test" omitted + +# Unsupported target "suggestions" with type "test" omitted + +# Unsupported target "supports" with type "test" omitted diff --git a/third_party/cargo/vendor/darling-0.10.2/CHANGELOG.md b/third_party/cargo/vendor/darling-0.10.2/CHANGELOG.md new file mode 100644 index 0000000..9d75399 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/CHANGELOG.md @@ -0,0 +1,110 @@ +# Changelog + +## v0.10.2 (October 30, 2019) +- Bump syn dependency to 1.0.1 [#83](https://github.com/TedDriggs/darling/pull/83) + +## v0.10.1 (September 25, 2019) +- Fix test compilation errors [#81](https://github.com/TedDriggs/darling/pull/81) + +## v0.10.0 (August 15, 2019) +- Bump syn and quote to 1.0 [#79](https://github.com/TedDriggs/darling/pull/79) +- Increase rust version to 1.31 + +## v0.9.0 (March 20, 2019) +- Enable "did you mean" suggestions by default +- Make `darling_core::{codegen, options}` private [#58](https://github.com/TedDriggs/darling/issues/58) +- Fix `Override::as_mut`: [#66](https://github.com/TedDriggs/darling/issues/66) + +## v0.8.6 (March 18, 2019) +- Added "did you mean" suggestions for unknown fields behind the `suggestions` flag [#60](https://github.com/TedDriggs/issues/60) +- Added `Error::unknown_field_with_alts` to support the suggestion use-case. +- Added `ast::Fields::len` and `ast::Fields::is_empty` methods. + +## v0.8.5 (February 4, 2019) +- Accept unquoted positive numeric literals [#52](https://github.com/TedDriggs/issues/52) +- Add `FromMeta` to the `syn::Lit` enum and its variants +- Improve error message for unexpected literal formats to not say "other" + +## v0.8.4 (February 4, 2019) +- Use `syn::Error` to provide precise errors before `proc_macro::Diagnostic` is available +- Add `diagnostics` feature flag to toggle between stable and unstable error backends +- Attach error information in more contexts +- Add `allow_unknown_fields` to support parsing the same attribute multiple times for different macros [#51](https://github.com/darling/issues/51) +- Proc-macro authors will now see better errors in `darling` attributes + +## v0.8.3 (January 21, 2019) +- Attach spans to errors in generated trait impls [#37](https://github.com/darling/issues/37) +- Attach spans to errors for types with provided bespoke implementations +- Deprecate `set_span` from 0.8.2, as spans should never be broadened after being initially set + +## v0.8.2 (January 17, 2019) +- Add spans to errors to make quality warnings and errors easy in darling. This is blocked on diagnostics stabilizing. +- Add `darling::util::SpannedValue` so proc-macro authors can remember position information alongside parsed values. + +## v0.8.0 +- Update dependency on `syn` to 0.15 [#44](https://github.com/darling/pull/44). Thanks to @hcpl + +## v0.7.0 (July 24, 2018) +- Update dependencies on `syn` and `proc-macro2` +- Add `util::IdentString`, which acts as an Ident or its string equivalent + +## v0.6.3 (May 22, 2018) +- Add support for `Uses*` traits in where predicates + +## v0.6.2 (May 22, 2018) +- Add `usage` module for tracking type param and lifetime usage in generic declarations + - Add `UsesTypeParams` and `CollectsTypeParams` traits [#37](https://github.com/darling/issues/37) + - Add `UsesLifetimes` and `CollectLifetimes` traits [#41](https://github.com/darling/pull/41) +- Don't add `FromMeta` bounds to type parameters only used by skipped fields [#40](https://github.com/darling/pull/40) + +## v0.6.1 (May 17, 2018) +- Fix an issue where the `syn` update broke shape validation [#36](https://github.com/TedDriggs/darling/issues/36) + +## v0.6.0 (May 15, 2018) + +### Breaking Changes +- Renamed `FromMetaItem` to `FromMeta`, and renamed `from_meta_item` method to `from_meta` +- Added dedicated `derive(FromMetaItem)` which panics and redirects users to `FromMeta` + +## v0.5.0 (May 10, 2018) +- Add `ast::Generics` and `ast::GenericParam` to work with generics in a manner similar to `ast::Data` +- Add `ast::GenericParamExt` to support alternate representations of generic parameters +- Add `util::WithOriginal` to get a parsed representation and syn's own struct for a syntax block +- Add `FromGenerics` and `FromGenericParam` traits (without derive support) +- Change generated code for `generics` magic field to invoke `FromGenerics` trait during parsing +- Add `FromTypeParam` trait [#30](https://github.com/TedDriggs/darling/pull/30). Thanks to @upsuper + +## v0.4.0 (April 5, 2018) +- Update dependencies on `proc-macro`, `quote`, and `syn` [#26](https://github.com/TedDriggs/darling/pull/26). Thanks to @hcpl + +## v0.3.3 (April 2, 2018) +**YANKED** + +## v0.3.2 (March 13, 2018) +- Derive `Default` on `darling::Ignored` (fixes [#25](https://github.com/TedDriggs/darling/issues/25)). + +## v0.3.1 (March 7, 2018) +- Support proc-macro2/nightly [#24](https://github.com/TedDriggs/darling/pull/24). Thanks to @kdy1 + +## v0.3.0 (January 26, 2018) + +### Breaking Changes +- Update `syn` to 0.12 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong +- Update `quote` to 0.4 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong +- Rename magic field `body` in derived `FromDeriveInput` structs to `data` to stay in sync with `syn` +- Rename magic field `data` in derived `FromVariant` structs to `fields` to stay in sync with `syn` + +## v0.2.2 (December 5, 2017) + +- Update `lazy_static` to 1.0 [#15](https://github.com/TedDriggs/darling/pull/16). Thanks to @Eijebong + +## v0.2.1 (November 28, 2017) + +- Add `impl FromMetaItem` for integer types [#15](https://github.com/TedDriggs/darling/pull/15) + +## v0.2.0 (June 18, 2017) + +- Added support for returning multiple errors from parsing [#5](https://github.com/TedDriggs/darling/pull/5) +- Derived impls no longer return on first error [#5](https://github.com/TedDriggs/darling/pull/5) +- Removed default types for `V` and `F` from `ast::Body` +- Enum variants are automatically converted to snake_case [#12](https://github.com/TedDriggs/darling/pull/12) diff --git a/third_party/cargo/vendor/darling-0.10.2/Cargo.lock b/third_party/cargo/vendor/darling-0.10.2/Cargo.lock new file mode 100644 index 0000000..2b767e5 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/Cargo.lock @@ -0,0 +1,92 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "darling" +version = "0.10.2" +dependencies = [ + "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ident_case" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum darling_core 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa" +"checksum proc-macro2 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "19f287c234c9b2d0308d692dee5c449c1a171167a6f8150f7cf2a49d8fd96967" +"checksum quote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ab938ebe6f1c82426b5fb82eaf10c3e3028c53deaa3fbe38f5904b37cf4d767" +"checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" +"checksum syn 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "863ecbce06044c8380458360b4146d7372edadfedd77f120ba8c193da427b708" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/third_party/cargo/vendor/darling-0.10.2/Cargo.toml b/third_party/cargo/vendor/darling-0.10.2/Cargo.toml new file mode 100644 index 0000000..2fff9cd --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "darling" +version = "0.10.2" +authors = ["Ted Driggs "] +exclude = ["/.travis.yml", "/publish.sh"] +description = "A proc-macro library for reading attributes into structs when\nimplementing custom derives.\n" +documentation = "https://docs.rs/darling/0.10.2" +readme = "README.md" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" +[dependencies.darling_core] +version = "=0.10.2" + +[dependencies.darling_macro] +version = "=0.10.2" +[dev-dependencies.proc-macro2] +version = "1" + +[dev-dependencies.quote] +version = "1" + +[dev-dependencies.syn] +version = "1" + +[features] +default = ["suggestions"] +diagnostics = ["darling_core/diagnostics"] +suggestions = ["darling_core/suggestions"] +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "TedDriggs/darling" diff --git a/third_party/cargo/vendor/darling-0.10.2/LICENSE b/third_party/cargo/vendor/darling-0.10.2/LICENSE new file mode 100644 index 0000000..0b48ead --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/cargo/vendor/darling-0.10.2/README.md b/third_party/cargo/vendor/darling-0.10.2/README.md new file mode 100644 index 0000000..24e46d9 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/README.md @@ -0,0 +1,113 @@ +Darling +======= + +[![Build Status](https://travis-ci.org/TedDriggs/darling.svg?branch=master)](https://travis-ci.org/TedDriggs/darling) +[![Latest Version](https://img.shields.io/crates/v/darling.svg)](https://crates.io/crates/darling) +[![Rustc Version 1.31+](https://img.shields.io/badge/rustc-1.31+-lightgray.svg)](https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html) + +`darling` is a crate for proc macro authors, which enables parsing attributes into structs. It is heavily inspired by `serde` both in its internals and in its API. + +# Benefits +* Easy and declarative parsing of macro input - make your proc-macros highly controllable with minimal time investment. +* Great validation and errors, no work required. When users of your proc-macro make a mistake, `darling` makes sure they get error markers at the right place in their source, and provides "did you mean" suggestions for misspelled fields. + +# Usage +`darling` provides a set of traits which can be derived or manually implemented. + +1. `FromMeta` is used to extract values from a meta-item in an attribute. Implementations are likely reusable for many libraries, much like `FromStr` or `serde::Deserialize`. Trait implementations are provided for primitives, some std types, and some `syn` types. +2. `FromDeriveInput` is implemented or derived by each proc-macro crate which depends on `darling`. This is the root for input parsing; it gets access to the identity, generics, and visibility of the target type, and can specify which attribute names should be parsed or forwarded from the input AST. +3. `FromField` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity (if it exists), type, and visibility of the field. +4. `FromVariant` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity and contents of the variant, which can be transformed the same as any other `darling` input. + +## Additional Modules +* `darling::ast` provides generic types for representing the AST. +* `darling::usage` provides traits and functions for determining where type parameters and lifetimes are used in a struct or enum. +* `darling::util` provides helper types with special `FromMeta` implementations, such as `IdentList`. + +# Example + +```rust,ignore +#[macro_use] +extern crate darling; +extern crate syn; + +#[derive(Default, FromMeta)] +#[darling(default)] +pub struct Lorem { + #[darling(rename = "sit")] + ipsum: bool, + dolor: Option, +} + +#[derive(FromDeriveInput)] +#[darling(from_ident, attributes(my_crate), forward_attrs(allow, doc, cfg))] +pub struct MyTraitOpts { + ident: syn::Ident, + attrs: Vec, + lorem: Lorem, +} +``` + +The above code will then be able to parse this input: + +```rust,ignore +/// A doc comment which will be available in `MyTraitOpts::attrs`. +#[derive(MyTrait)] +#[my_crate(lorem(dolor = "Hello", ipsum))] +pub struct ConsumingType; +``` + +# Attribute Macros +Non-derive attribute macros are supported. +To parse arguments for attribute macros, derive `FromMeta` on the argument receiver type, then pass `&syn::AttributeArgs` to the `from_list` method. +This will produce a normal `darling::Result` that can be used the same as a result from parsing a `DeriveInput`. + +## Macro Code +```rust,ignore +use darling::FromMeta; +use syn::{AttributeArgs, ItemFn}; +use proc_macro::TokenStream; + +#[derive(Debug, FromMeta)] +pub struct MacroArgs { + #[darling(default)] + timeout_ms: Option, + path: String, +} + +#[proc_macro_attribute] +fn your_attr(args: TokenStream, input: TokenStream) -> TokenStream { + let attr_args = parse_macro_input!(args as AttributeArgs); + let _input = parse_macro_input!(input as ItemFn); + + let _args = match MacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { return e.write_errors(); } + }; + + // do things with `args` + unimplemented!() +} +``` + +## Consuming Code +```rust,ignore +use your_crate::your_attr; + +#[your_attr(path = "hello", timeout_ms = 15)] +fn do_stuff() { + println!("Hello"); +} +``` + +# Features +Darling's features are built to work well for real-world projects. + +* **Defaults**: Supports struct- and field-level defaults, using the same path syntax as `serde`. +* **Field Renaming**: Fields can have different names in usage vs. the backing code. +* **Auto-populated fields**: Structs deriving `FromDeriveInput` and `FromField` can declare properties named `ident`, `vis`, `ty`, `attrs`, and `generics` to automatically get copies of the matching values from the input AST. `FromDeriveInput` additionally exposes `data` to get access to the body of the deriving type, and `FromVariant` exposes `fields`. +* **Mapping function**: Use `#[darling(map="path")]` to specify a function that runs on the result of parsing a meta-item field. This can change the return type, which enables you to parse to an intermediate form and convert that to the type you need in your struct. +* **Skip fields**: Use `#[darling(skip)]` to mark a field that shouldn't be read from attribute meta-items. +* **Multiple-occurrence fields**: Use `#[darling(multiple)]` on a `Vec` field to allow that field to appear multiple times in the meta-item. Each occurrence will be pushed into the `Vec`. +* **Span access**: Use `darling::util::SpannedValue` in a struct to get access to that meta item's source code span. This can be used to emit warnings that point at a specific field from your proc macro. In addition, you can use `darling::Error::write_errors` to automatically get precise error location details in most cases. +* **"Did you mean" suggestions**: Compile errors from derived darling trait impls include suggestions for misspelled fields. \ No newline at end of file diff --git a/third_party/cargo/vendor/darling-0.10.2/examples/automatic_bounds.rs b/third_party/cargo/vendor/darling-0.10.2/examples/automatic_bounds.rs new file mode 100644 index 0000000..73e236b --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/examples/automatic_bounds.rs @@ -0,0 +1,78 @@ +#[macro_use] +extern crate darling; + +extern crate syn; + +use darling::FromDeriveInput; + +#[derive(FromMeta, PartialEq, Eq, Debug)] +enum Volume { + Whisper, + Talk, + Shout, +} + +/// A more complex example showing the ability to skip at a field or struct +/// level while still tracking which type parameters need to be bounded. +/// This can be seen by expanding this example using `cargo expand`. +#[derive(FromMeta)] +#[allow(dead_code)] +enum Emphasis { + Constant(Volume), + Variable(darling::util::PathList), + #[darling(skip)] + PerPhoneme(Option), + Strided { + #[darling(skip)] + step: Vec, + #[darling(multiple)] + volume: Vec, + }, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +struct SpeakingOptions { + max_volume: U, + #[darling(skip, default)] + additional_data: Vec, +} + +#[derive(Default)] +struct Phoneme { + #[allow(dead_code)] + first: String, +} + +// This is probably the holy grail for `darling`'s own internal use-case: +// Auto-apply `Default` bound to skipped *field* types in `where` clause. +impl Default for SpeakingOptions +where + Vec: Default, + U: Default, +{ + fn default() -> Self { + Self { + max_volume: Default::default(), + additional_data: Default::default(), + } + } +} + +fn main() { + let derive_input = syn::parse_str( + r#" + #[derive(Speak)] + #[speak(max_volume = "shout")] + enum HtmlElement { + Div(String) + } + "#, + ) + .unwrap(); + + let parsed: SpeakingOptions = + FromDeriveInput::from_derive_input(&derive_input).unwrap(); + assert_eq!(parsed.max_volume, Volume::Shout); + assert_eq!(parsed.additional_data.len(), 0); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/examples/consume_fields.rs b/third_party/cargo/vendor/darling-0.10.2/examples/consume_fields.rs new file mode 100644 index 0000000..4b0703f --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/examples/consume_fields.rs @@ -0,0 +1,175 @@ +//! This example shows how to do struct and field parsing using darling. + +#[macro_use] +extern crate darling; +extern crate proc_macro2; +#[macro_use] +extern crate quote; +extern crate syn; + +use darling::ast; +use darling::FromDeriveInput; +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::parse_str; + +/// A speaking volume. Deriving `FromMeta` will cause this to be usable +/// as a string value for a meta-item key. +#[derive(Debug, Clone, Copy, FromMeta)] +#[darling(default)] +enum Volume { + Normal, + Whisper, + Shout, +} + +impl Default for Volume { + fn default() -> Self { + Volume::Normal + } +} + +/// Support parsing from a full derive input. Unlike FromMeta, this isn't +/// composable; each darling-dependent crate should have its own struct to handle +/// when its trait is derived. +#[derive(Debug, FromDeriveInput)] +// This line says that we want to process all attributes declared with `my_trait`, +// and that darling should panic if this receiver is given an enum. +#[darling(attributes(my_trait), supports(struct_any))] +struct MyInputReceiver { + /// The struct ident. + ident: syn::Ident, + + /// The type's generics. You'll need these any time your trait is expected + /// to work with types that declare generics. + generics: syn::Generics, + + /// Receives the body of the struct or enum. We don't care about + /// struct fields because we previously told darling we only accept structs. + data: ast::Data<(), MyFieldReceiver>, + + /// The Input Receiver demands a volume, so use `Volume::Normal` if the + /// caller doesn't provide one. + #[darling(default)] + volume: Volume, +} + +impl ToTokens for MyInputReceiver { + fn to_tokens(&self, tokens: &mut TokenStream) { + let MyInputReceiver { + ref ident, + ref generics, + ref data, + volume, + } = *self; + + let (imp, ty, wher) = generics.split_for_impl(); + let fields = data + .as_ref() + .take_struct() + .expect("Should never be enum") + .fields; + + // Generate the format string which shows each field and its name + let fmt_string = fields + .iter() + .enumerate() + .map(|(i, f)| { + // We have to preformat the ident in this case so we can fall back + // to the field index for unnamed fields. It's not easy to read, + // unfortunately. + format!( + "{} = {{}}", + f.ident + .as_ref() + .map(|v| format!("{}", v)) + .unwrap_or_else(|| format!("{}", i)) + ) + }) + .collect::>() + .join(", "); + + // Generate the actual values to fill the format string. + let field_list = fields + .into_iter() + .enumerate() + .map(|(i, f)| { + let field_volume = f.volume.unwrap_or(volume); + + // This works with named or indexed fields, so we'll fall back to the index so we can + // write the output as a key-value pair. + let field_ident = f.ident + .as_ref() + .map(|v| quote!(#v)) + .unwrap_or_else(|| quote!(#i)); + + match field_volume { + Volume::Normal => quote!(self.#field_ident), + Volume::Shout => { + quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase()) + } + Volume::Whisper => { + quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase()) + } + } + }) + .collect::>(); + + tokens.extend(quote! { + impl #imp Speak for #ident #ty #wher { + fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(#fmt_string, #(#field_list),*) + } + } + }); + } +} + +#[derive(Debug, FromField)] +#[darling(attributes(my_trait))] +struct MyFieldReceiver { + /// Get the ident of the field. For fields in tuple or newtype structs or + /// enum bodies, this can be `None`. + ident: Option, + + /// This magic field name pulls the type from the input. + ty: syn::Type, + + /// We declare this as an `Option` so that during tokenization we can write + /// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level + /// overrides of struct-level settings. + #[darling(default)] + volume: Option, +} + +fn main() { + let input = r#"#[derive(MyTrait)] +#[my_trait(volume = "shout")] +pub struct Foo { + #[my_trait(volume = "whisper")] + bar: bool, + + baz: i64, +}"#; + + let parsed = parse_str(input).unwrap(); + let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); + let tokens = quote!(#receiver); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + +EMITS: + +{} + "#, + input, receiver, tokens + ); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/examples/fallible_read.rs b/third_party/cargo/vendor/darling-0.10.2/examples/fallible_read.rs new file mode 100644 index 0000000..c487854 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/examples/fallible_read.rs @@ -0,0 +1,87 @@ +//! This example demonstrates techniques for performing custom error handling +//! in a derive-input receiver. +//! +//! 1. Using `darling::Result` as a carrier to preserve the error for later display +//! 1. Using `Result` to attempt a recovery in imperative code +//! 1. Using the `map` darling meta-item to post-process the receiver before returning. +#[macro_use] +extern crate darling; + +extern crate syn; + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_str; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(my_trait), map = "MyInputReceiver::autocorrect")] +pub struct MyInputReceiver { + /// This field must be present and a string or else parsing will panic. + name: String, + + /// If this field fails to parse, the struct can still be built; the field + /// will contain the error. The consuming struct can then decide if this + /// blocks code generation. If so, panic. Otherwise, recover and proceed. + frequency: darling::Result, + + /// If this field fails to parse, the struct can still be built; the field + /// will contain an `Err` with the original `syn::Meta`. This can be used + /// for alternate parsing attempts before panicking. + amplitude: Result, +} + +impl MyInputReceiver { + /// This function will be called by `darling` _after_ it's finished parsing the + /// input but before returning to the caller. This is a good place to initialize + /// skipped fields or to perform corrections that don't lend themselves to being + /// done elsewhere. + fn autocorrect(self) -> Self { + let Self { + name, + frequency, + amplitude, + } = self; + + // Amplitude doesn't have a sign, so if we received a negative number then + // we'll go ahead and make it positive. + let amplitude = match amplitude { + Ok(amp) => amp, + Err(mi) => { + let val: i64 = if let Ok(v) = FromMeta::from_meta(&mi) { + v + } else { + panic!(format!("amplitude should have been an integer")) + }; + + val.abs() as u64 + } + }; + + Self { + name, + frequency, + amplitude: Ok(amplitude), + } + } +} + +fn main() { + let input = r#"#[derive(MyTrait)] +#[my_trait(name="Jon", amplitude = "-1", frequency = "1")] +pub struct Foo;"#; + + let parsed = parse_str(input).unwrap(); + let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + "#, + input, receiver + ); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/examples/supports_struct.rs b/third_party/cargo/vendor/darling-0.10.2/examples/supports_struct.rs new file mode 100644 index 0000000..dbf8238 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/examples/supports_struct.rs @@ -0,0 +1,62 @@ +#[macro_use] +extern crate darling; + +extern crate syn; + +use darling::{ast, util, FromDeriveInput}; +use syn::{Ident, Type}; + +#[derive(Debug, FromField)] +#[darling(attributes(lorem))] +pub struct LoremField { + ident: Option, + ty: Type, + #[darling(default)] + skip: bool, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(lorem), supports(struct_named))] +pub struct Lorem { + ident: Ident, + data: ast::Data, +} + +fn main() { + let good_input = r#"#[derive(Lorem)] +pub struct Foo { + #[lorem(skip)] + bar: bool, + + baz: i64, +}"#; + + let bad_input = r#"#[derive(Lorem)] + pub struct BadFoo(String, u32);"#; + + let parsed = syn::parse_str(good_input).unwrap(); + let receiver = Lorem::from_derive_input(&parsed).unwrap(); + let wrong_shape_parsed = syn::parse_str(bad_input).unwrap(); + let wrong_shape = Lorem::from_derive_input(&wrong_shape_parsed).expect_err("Shape was wrong"); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + +BAD INPUT: + +{} + +PRODUCED ERROR: + +{} + "#, + good_input, receiver, bad_input, wrong_shape + ); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/src/lib.rs b/third_party/cargo/vendor/darling-0.10.2/src/lib.rs new file mode 100644 index 0000000..70035be --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/src/lib.rs @@ -0,0 +1,98 @@ +//! # Darling +//! Darling is a tool for declarative attribute parsing in proc macro implementations. +//! +//! +//! ## Design +//! Darling takes considerable design inspiration from [`serde`]. A data structure that can be +//! read from any attribute implements `FromMeta` (or has an implementation automatically +//! generated using `derive`). Any crate can provide `FromMeta` implementations, even one not +//! specifically geared towards proc-macro authors. +//! +//! Proc-macro crates should provide their own structs which implement or derive `FromDeriveInput`, +//! `FromField`, `FromVariant`, `FromGenerics`, _et alia_ to gather settings relevant to their operation. +//! +//! ## Attributes +//! There are a number of attributes that `darling` exposes to enable finer-grained control over the code +//! it generates. +//! +//! * **Field renaming**: You can use `#[darling(rename="new_name")]` on a field to change the name Darling looks for. +//! You can also use `#[darling(rename_all="...")]` at the struct or enum level to apply a casing rule to all fields or variants. +//! * **Map function**: You can use `#[darling(map="path::to::function")]` to run code on a field before its stored in the struct. +//! * **Default values**: You can use `#[darling(default)]` at the type or field level to use that type's default value to fill +//! in values not specified by the caller. +//! * **Skipped fields**: You can skip a variant or field using `#[darling(skip)]`. Fields marked with this will fall back to +//! `Default::default()` for their value, but you can override that with an explicit default or a value from the type-level default. +//! +//! ## Forwarded Fields +//! All derivable traits except `FromMeta` support forwarding some fields from the input AST to the derived struct. +//! These fields are matched up by identifier **before** `rename` attribute values are considered, +//! allowing you to use their names for your own properties. +//! The deriving struct is responsible for making sure the types of fields it chooses to declare are compatible with this table. +//! +//! A deriving struct is free to include or exclude any of the fields below. +//! +//! ### `FromDeriveInput` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in type| +//! |`vis`|`syn::Visibility`|The visibility of the passed-in type| +//! |`generics`|`T: darling::FromGenerics`|The generics of the passed-in type. This can be `syn::Generics`, `darling::ast::Generics`, or any compatible type.| +//! |`data`|`darling::ast::Data`|The body of the passed-in type| +//! |`attrs`|`Vec`|The forwarded attributes from the passed in type. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromField` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in field| +//! |`vis`|`syn::Visibility`|The visibility of the passed-in field| +//! |`ty`|`syn::Type`|The type of the passed-in field| +//! |`attrs`|`Vec`|The forwarded attributes from the passed in field. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromTypeParam` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in type param| +//! |`bounds`|`Vec`|The bounds applied to the type param| +//! |`default`|`Option`|The default type of the parameter, if one exists| +//! |`attrs`|`Vec`|The forwarded attributes from the passed in type param. These are controlled using the `forward_attrs` attribute.| + +extern crate core; +extern crate darling_core; + +#[allow(unused_imports)] +#[macro_use] +extern crate darling_macro; + +#[doc(hidden)] +pub use darling_macro::*; + +#[doc(inline)] +pub use darling_core::{FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, + FromTypeParam, FromVariant}; + +#[doc(inline)] +pub use darling_core::{Error, Result}; + +#[doc(inline)] +pub use darling_core::{ast, error, usage, util}; + +// XXX exported so that `ExtractAttribute::extractor` can convert a path into tokens. +// This is likely to change in the future, so only generated code should depend on this export. +#[doc(hidden)] +pub use darling_core::ToTokens; + +/// Core/std trait re-exports. This should help produce generated code which doesn't +/// depend on `std` unnecessarily, and avoids problems caused by aliasing `std` or any +/// of the referenced types. +#[doc(hidden)] +pub mod export { + pub use core::convert::From; + pub use core::default::Default; + pub use core::option::Option::{self, None, Some}; + pub use core::result::Result::{self, Err, Ok}; + pub use std::vec::Vec; + pub use std::string::ToString; +} + +#[macro_use] +mod macros_public; diff --git a/third_party/cargo/vendor/darling-0.10.2/src/macros_public.rs b/third_party/cargo/vendor/darling-0.10.2/src/macros_public.rs new file mode 100644 index 0000000..a3c5cac --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/src/macros_public.rs @@ -0,0 +1,98 @@ +//! Macros that should be exported from both `darling_core` and `darling`. +//! Note that these are **sym-linked** into the main code, and so cannot declare on items that are exported differently +//! in `darling_core` vs. `darling`. + +/// Generator for `UsesTypeParam` impls that unions the used type parameters of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesTypeParams`, or the resulting code won't compile. +/// +/// ```rust +/// # extern crate syn; +/// # +/// # #[macro_use] +/// # extern crate darling_core; +/// # +/// struct MyField { +/// ty: syn::Type, +/// } +/// +/// uses_type_params!(MyField, ty); +/// +/// fn main() { +/// // no test run +/// } +/// ``` +/// +/// `darling` cannot derive this trait automatically, as it doesn't know which information extracted from +/// proc-macro input is meant to constitute "using" the type parameter, but crate consumers should +/// implement it by hand or using the macro. +#[macro_export] +macro_rules! uses_type_params { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + self.$accessor.uses_type_params(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + let mut hits = self.$first.uses_type_params(options, type_set); + $( + hits.extend(self.$field.uses_type_params(options, type_set)); + )* + hits + } + } + }; +} + +/// Generator for `UsesLifetimes` impls that unions the used lifetimes of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesLifetimes`, or the resulting code won't compile. +#[macro_export] +macro_rules! uses_lifetimes { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + self.$accessor.uses_lifetimes(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + let mut hits = self.$first.uses_lifetimes(options, type_set); + $( + hits.extend(self.$field.uses_lifetimes(options, type_set)); + )* + hits + } + } + }; +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/accrue_errors.rs b/third_party/cargo/vendor/darling-0.10.2/tests/accrue_errors.rs new file mode 100644 index 0000000..9ae8212 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/accrue_errors.rs @@ -0,0 +1,108 @@ +//! These tests verify that multiple errors will be collected up from throughout +//! the parsing process and returned correctly to the caller. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::ast; +use darling::FromDeriveInput; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(accrue))] +struct Lorem { + ipsum: String, + dolor: Dolor, + data: ast::Data<(), LoremField>, +} + +#[derive(Debug, FromMeta)] +struct Dolor { + sit: bool, +} + +#[derive(Debug, FromField)] +#[darling(attributes(accrue))] +struct LoremField { + ident: Option, + aliased_as: syn::Ident, +} + +#[test] +fn bad_type_and_missing_fields() { + let input = parse_quote! { + #[accrue(ipsum = true, dolor(amet = "Hi"))] + pub struct NonConforming { + foo: () + } + }; + + let s_result: ::darling::Error = Lorem::from_derive_input(&input).unwrap_err(); + let err = s_result.flatten(); + println!("{}", err); + assert_eq!(3, err.len()); +} + +#[test] +fn body_only_issues() { + let input = parse_quote! { + #[accrue(ipsum = "Hello", dolor(sit))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Lorem::from_derive_input(&input).unwrap_err(); + println!("{:?}", s_err); + assert_eq!(2, s_err.len()); +} + +#[derive(Debug, FromMeta)] +enum Week { + Monday, + Tuesday { morning: bool, afternoon: String }, + Wednesday(Dolor), +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(accrue))] +struct Month { + schedule: Week, +} + +#[test] +fn error_in_enum_fields() { + let input = parse_quote! { + #[accrue(schedule(tuesday(morning = "yes")))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Month::from_derive_input(&input).unwrap_err(); + assert_eq!(2, s_err.len()); + let err = s_err.flatten(); + // TODO add tests to check location path is correct + println!("{}", err); +} + +#[test] +fn error_in_newtype_variant() { + let input = parse_quote! { + #[accrue(schedule(wednesday(sit = "yes")))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Month::from_derive_input(&input).unwrap_err(); + assert_eq!(1, s_err.len()); + println!("{}", s_err); + println!("{}", s_err.flatten()); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/computed_bound.rs b/third_party/cargo/vendor/darling-0.10.2/tests/computed_bound.rs new file mode 100644 index 0000000..94fd307 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/computed_bound.rs @@ -0,0 +1,46 @@ +#[macro_use] +extern crate darling; +extern crate syn; + +use darling::FromDeriveInput; + +fn parse(src: &str) -> T { + let ast = syn::parse_str(src).unwrap(); + FromDeriveInput::from_derive_input(&ast).unwrap() +} + +#[derive(FromMeta, PartialEq, Eq, Debug)] +enum Volume { + Whisper, + Talk, + Shout, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +struct SpeakingOptions { + max_volume: U, + #[darling(skip)] + #[allow(dead_code)] + additional_data: T, +} + +#[derive(Default)] +struct Phoneme { + #[allow(dead_code)] + first: String, +} + +#[test] +fn skipped_field() { + let parsed: SpeakingOptions = parse( + r#" + #[derive(Speak)] + #[speak(max_volume = "shout")] + enum HtmlElement { + Div(String) + } + "#, + ); + assert_eq!(parsed.max_volume, Volume::Shout); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/custom_bound.rs b/third_party/cargo/vendor/darling-0.10.2/tests/custom_bound.rs new file mode 100644 index 0000000..4266a74 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/custom_bound.rs @@ -0,0 +1,25 @@ +#[macro_use] +extern crate darling; +extern crate syn; + +use std::ops::Add; + +#[derive(Debug, Clone, FromMeta)] +#[darling(bound = "T: FromMeta + Add")] +struct Wrapper(pub T); + +impl Add for Wrapper { + type Output = Wrapper<::Output>; + fn add(self, rhs: Self) -> Wrapper<::Output> { + Wrapper(self.0 + rhs.0) + } +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(hello), bound = "Wrapper: Add, T: FromMeta")] +struct Foo { + lorem: Wrapper, +} + +#[test] +fn expansion() {} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/defaults.rs b/third_party/cargo/vendor/darling-0.10.2/tests/defaults.rs new file mode 100644 index 0000000..c6003ec --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/defaults.rs @@ -0,0 +1,32 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; + +use darling::FromDeriveInput; + +mod foo { + pub mod bar { + pub fn init() -> String { + String::from("hello") + } + } +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +pub struct SpeakerOpts { + #[darling(default="foo::bar::init")] + first_word: String, +} + +#[test] +fn path_default() { + let speaker: SpeakerOpts = FromDeriveInput::from_derive_input(&parse_quote! { + struct Foo; + }).expect("Unit struct with no attrs should parse"); + + assert_eq!(speaker.first_word, "hello"); +} \ No newline at end of file diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/enums_newtype.rs b/third_party/cargo/vendor/darling-0.10.2/tests/enums_newtype.rs new file mode 100644 index 0000000..0fd12f0 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/enums_newtype.rs @@ -0,0 +1,96 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Debug, Default, PartialEq, Eq, FromMeta)] +#[darling(default)] +pub struct Amet { + hello: bool, + world: String, +} + +#[derive(Debug, PartialEq, Eq, FromMeta)] +#[darling(rename_all = "snake_case")] +pub enum Lorem { + Ipsum(bool), + Dolor(String), + Sit(Amet), +} + +#[derive(Debug, PartialEq, Eq, FromDeriveInput)] +#[darling(attributes(hello))] +pub struct Holder { + lorem: Lorem, +} + +impl PartialEq for Holder { + fn eq(&self, other: &Lorem) -> bool { + self.lorem == *other + } +} + +#[test] +fn bool_word() { + let di = parse_quote! { + #[hello(lorem(ipsum))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Ipsum(true)); +} + +#[test] +fn bool_literal() { + let di = parse_quote! { + #[hello(lorem(ipsum = false))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Ipsum(false)); +} + +#[test] +fn string_literal() { + let di = parse_quote! { + #[hello(lorem(dolor = "Hello"))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Dolor("Hello".to_string())); +} + +#[test] +fn struct_nested() { + let di = parse_quote! { + #[hello(lorem(sit(world = "Hello", hello = false)))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!( + pr, + Lorem::Sit(Amet { + hello: false, + world: "Hello".to_string(), + }) + ); +} + +#[test] +#[should_panic] +fn format_mismatch() { + let di = parse_quote! { + #[hello(lorem(dolor(world = "Hello", hello = false)))] + pub struct Bar; + }; + + Holder::from_derive_input(&di).unwrap(); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/enums_struct.rs b/third_party/cargo/vendor/darling-0.10.2/tests/enums_struct.rs new file mode 100644 index 0000000..63ce690 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/enums_struct.rs @@ -0,0 +1,16 @@ +//! Test expansion of enums which have struct variants. + +#[macro_use] +extern crate darling; +extern crate syn; + +#[derive(Debug, FromMeta)] +#[darling(rename_all = "snake_case")] +enum Message { + Hello { user: String, silent: bool }, + Ping, + Goodbye { user: String }, +} + +#[test] +fn expansion() {} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/enums_unit.rs b/third_party/cargo/vendor/darling-0.10.2/tests/enums_unit.rs new file mode 100644 index 0000000..f9eb23f --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/enums_unit.rs @@ -0,0 +1,16 @@ +//! Test expansion of enum variants which have no associated data. + +#[macro_use] +extern crate darling; +extern crate syn; + +#[derive(Debug, FromMeta)] +#[darling(rename_all = "snake_case")] +enum Pattern { + Owned, + Immutable, + Mutable, +} + +#[test] +fn expansion() {} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/error.rs b/third_party/cargo/vendor/darling-0.10.2/tests/error.rs new file mode 100644 index 0000000..edd72eb --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/error.rs @@ -0,0 +1,55 @@ +//! In case of bad input, parsing should fail. The error should have locations set in derived implementations. +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Debug, FromMeta)] +struct Dolor { + #[darling(rename = "amet")] + sit: bool, + world: bool, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(from_ident, attributes(hello))] +struct Lorem { + ident: syn::Ident, + ipsum: Dolor, +} + +impl From for Lorem { + fn from(ident: syn::Ident) -> Self { + Lorem { + ident, + ipsum: Dolor { + sit: false, + world: true, + }, + } + } +} + +#[test] +fn parsing_fail() { + let di = parse_quote! { + #[hello(ipsum(amet = "yes", world = false))] + pub struct Foo; + }; + + println!("{}", Lorem::from_derive_input(&di).unwrap_err()); +} + +#[test] +fn missing_field() { + let di = parse_quote! { + #[hello(ipsum(amet = true))] + pub struct Foo; + }; + + println!("{}", Lorem::from_derive_input(&di).unwrap_err()); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/from_generics.rs b/third_party/cargo/vendor/darling-0.10.2/tests/from_generics.rs new file mode 100644 index 0000000..2c259ec --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/from_generics.rs @@ -0,0 +1,186 @@ +//! Tests for `FromGenerics`, and - indirectly - `FromGenericParam`. +//! These tests assume `FromTypeParam` is working and only look at whether the wrappers for magic +//! fields are working as expected. + +#[macro_use] +extern crate darling; +extern crate syn; + +use darling::ast::{self, GenericParamExt}; +use darling::util::{Ignored, WithOriginal}; +use darling::{FromDeriveInput, Result}; + +#[derive(FromDeriveInput)] +#[darling(attributes(lorem))] +struct MyReceiver { + pub ident: syn::Ident, + pub generics: ast::Generics>, +} + +#[derive(FromTypeParam)] +#[darling(attributes(lorem))] +struct MyTypeParam { + pub ident: syn::Ident, + #[darling(default)] + pub foo: bool, + #[darling(default)] + pub bar: Option, +} + +fn fdi(src: &str) -> Result { + FromDeriveInput::from_derive_input(&syn::parse_str(src).expect("Source parses")) +} + +/// Verify that `ast::Generics` is populated correctly when there is no generics declaration +#[test] +fn no_generics() { + let rec: MyReceiver = fdi("struct Baz;").expect("Input is well-formed"); + assert!(rec.generics.where_clause.is_none()); + assert_eq!(rec.generics.params.len(), 0); +} + +#[test] +fn expand_some() { + let rec: MyReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U); + "#) + .expect("Input is well-formed"); + assert!(rec.generics.where_clause.is_none()); + + // Make sure we've preserved the lifetime def, though we don't do anything with it. + assert!(rec.generics.params[0].as_lifetime_def().is_some()); + + let mut ty_param_iter = rec.generics.type_params(); + + let first = ty_param_iter + .next() + .expect("type_params should not be empty"); + assert!(first.bar.is_none()); + assert!(first.foo); + assert_eq!(first.ident, "T"); + + let second = ty_param_iter + .next() + .expect("type_params should have a second value"); + assert_eq!( + second + .bar + .as_ref() + .expect("Second type param should set bar"), + "x" + ); + assert_eq!(second.foo, false); + assert_eq!(second.ident, "U"); +} + +/// Verify ≤0.4.1 behavior - where `generics` had to be `syn::Generics` - keeps working. +#[test] +fn passthrough() { + #[derive(FromDeriveInput)] + struct PassthroughReceiver { + pub generics: syn::Generics, + } + + let rec: PassthroughReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U); + "#) + .expect("Input is well-formed"); + + let mut type_param_iter = rec.generics.type_params(); + assert!(type_param_iter.next().is_some()); +} + +/// Verify that `where_clause` is passed through when it exists. +/// As of 0.4.1, there is no `FromWhereClause` trait, so other types aren't supported +/// for that field. +#[test] +fn where_clause() { + let rec: MyReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into; + "#) + .expect("Input is well-formed"); + + assert!(rec.generics.where_clause.is_some()); +} + +/// Test that `WithOriginal` works for generics. +#[test] +fn with_original() { + #[derive(FromDeriveInput)] + struct WorigReceiver { + generics: WithOriginal>, syn::Generics>, + } + + let rec: WorigReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into; + "#) + .expect("Input is well-formed"); + + // Make sure we haven't lost anything in the conversion + assert_eq!(rec.generics.parsed.params.len(), 3); + assert_eq!( + rec.generics + .original + .params + .iter() + .collect::>() + .len(), + 3 + ); + + let parsed_t: &MyTypeParam = rec.generics.parsed.params[1] + .as_type_param() + .expect("Second argument should be type param"); + + // Make sure the first type param in each case is T + assert_eq!(parsed_t.ident, "T"); + assert_eq!( + rec.generics + .original + .type_params() + .next() + .expect("First type param should exist") + .ident, + "T" + ); + + // Make sure we actually parsed the first type param + assert!(parsed_t.foo); + assert!(parsed_t.bar.is_none()); +} + +/// Make sure generics can be ignored +#[test] +fn ignored() { + #[derive(FromDeriveInput)] + struct IgnoredReceiver { + generics: Ignored, + } + + let rec: IgnoredReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into; + "#) + .expect("Input is well-formed"); + + assert_eq!(Ignored, rec.generics); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/from_type_param.rs b/third_party/cargo/vendor/darling-0.10.2/tests/from_type_param.rs new file mode 100644 index 0000000..adaf34d --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/from_type_param.rs @@ -0,0 +1,65 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromTypeParam; +use syn::{DeriveInput, GenericParam, Ident, TypeParam}; + +#[darling(attributes(lorem), from_ident)] +#[derive(FromTypeParam)] +struct Lorem { + ident: Ident, + bounds: Vec, + foo: bool, + bar: Option, +} + +impl From for Lorem { + fn from(ident: Ident) -> Self { + Lorem { + ident, + foo: false, + bar: None, + bounds: Default::default(), + } + } +} + +fn extract_type(param: &GenericParam) -> &TypeParam { + match *param { + GenericParam::Type(ref ty) => ty, + _ => unreachable!("Not a type param"), + } +} + +#[test] +fn expand_many() { + let di: DeriveInput = parse_quote! { + struct Baz< + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(T, U); + }; + + let params = di.generics.params; + + { + let ty = extract_type(¶ms[0]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.ident, "T"); + assert_eq!(lorem.foo, true); + assert_eq!(lorem.bar, None); + } + + { + let ty = extract_type(¶ms[1]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.ident, "U"); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, Some("x".to_string())); + assert_eq!(lorem.bounds.len(), 2); + } +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/from_type_param_default.rs b/third_party/cargo/vendor/darling-0.10.2/tests/from_type_param_default.rs new file mode 100644 index 0000000..eb0ecc7 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/from_type_param_default.rs @@ -0,0 +1,59 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromTypeParam; +use syn::{DeriveInput, GenericParam, TypeParam}; + +#[darling(attributes(lorem), default)] +#[derive(Default, FromTypeParam)] +struct Lorem { + foo: bool, + bar: Option, + default: Option, +} + +fn extract_type(param: &GenericParam) -> &TypeParam { + match *param { + GenericParam::Type(ref ty) => ty, + _ => unreachable!("Not a type param"), + } +} + +#[test] +fn expand_many() { + let di: DeriveInput = parse_quote! { + struct Baz< + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized, + #[lorem(foo = false)] V = (), + >(T, U, V); + }; + let params = di.generics.params; + + { + let ty = extract_type(¶ms[0]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, true); + assert_eq!(lorem.bar, None); + } + + { + let ty = extract_type(¶ms[1]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, Some("x".to_string())); + assert!(lorem.default.is_none()); + } + + { + let ty = extract_type(¶ms[2]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, None); + assert!(lorem.default.is_some()); + } +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/from_variant.rs b/third_party/cargo/vendor/darling-0.10.2/tests/from_variant.rs new file mode 100644 index 0000000..be216cb --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/from_variant.rs @@ -0,0 +1,27 @@ +#[macro_use] +extern crate darling; +extern crate syn; + +#[derive(FromVariant)] +#[darling(from_ident, attributes(hello))] +#[allow(dead_code)] +pub struct Lorem { + ident: syn::Ident, + into: Option, + skip: Option, + fields: darling::ast::Fields, +} + +impl From for Lorem { + fn from(ident: syn::Ident) -> Self { + Lorem { + ident, + into: Default::default(), + skip: Default::default(), + fields: darling::ast::Style::Unit.into(), + } + } +} + +#[test] +fn expansion() {} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/generics.rs b/third_party/cargo/vendor/darling-0.10.2/tests/generics.rs new file mode 100644 index 0000000..a83d03e --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/generics.rs @@ -0,0 +1,27 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Debug, Clone, FromMeta)] +struct Wrapper(pub T); + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(hello))] +struct Foo { + lorem: Wrapper, +} + +#[test] +fn expansion() { + let di = parse_quote! { + #[hello(lorem = "Hello")] + pub struct Foo; + }; + + Foo::::from_derive_input(&di).unwrap(); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/happy_path.rs b/third_party/cargo/vendor/darling-0.10.2/tests/happy_path.rs new file mode 100644 index 0000000..df1bfad --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/happy_path.rs @@ -0,0 +1,75 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Default, FromMeta, PartialEq, Debug)] +#[darling(default)] +struct Lorem { + ipsum: bool, + dolor: Option, +} + +#[derive(FromDeriveInput, PartialEq, Debug)] +#[darling(attributes(darling_demo))] +struct Core { + ident: syn::Ident, + vis: syn::Visibility, + generics: syn::Generics, + lorem: Lorem, +} + +#[derive(FromDeriveInput, PartialEq, Debug)] +#[darling(attributes(darling_demo))] +struct TraitCore { + ident: syn::Ident, + generics: syn::Generics, + lorem: Lorem, +} + +#[test] +fn simple() { + let di = parse_quote! { + #[derive(Foo)] + #[darling_demo(lorem(ipsum))] + pub struct Bar; + }; + + assert_eq!( + Core::from_derive_input(&di).unwrap(), + Core { + ident: parse_quote!(Bar), + vis: parse_quote!(pub), + generics: Default::default(), + lorem: Lorem { + ipsum: true, + dolor: None, + }, + } + ); +} + +#[test] +fn trait_type() { + let di = parse_quote! { + #[derive(Foo)] + #[darling_demo(lorem(dolor = "hello"))] + pub struct Bar; + }; + + assert_eq!( + TraitCore::from_derive_input(&di).unwrap(), + TraitCore { + ident: parse_quote!(Bar), + generics: Default::default(), + lorem: Lorem { + ipsum: false, + dolor: Some("hello".to_owned()), + } + } + ); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/multiple.rs b/third_party/cargo/vendor/darling-0.10.2/tests/multiple.rs new file mode 100644 index 0000000..e705280 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/multiple.rs @@ -0,0 +1,36 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(FromDeriveInput)] +#[darling(attributes(hello))] +#[allow(dead_code)] +struct Lorem { + ident: syn::Ident, + ipsum: Ipsum, +} + +#[derive(FromMeta)] +struct Ipsum { + #[darling(multiple)] + dolor: Vec, +} + +#[test] +fn expand_many() { + let di = parse_quote! { + #[hello(ipsum(dolor = "Hello", dolor = "World"))] + pub struct Baz; + }; + + let lorem: Lorem = Lorem::from_derive_input(&di).unwrap(); + assert_eq!( + lorem.ipsum.dolor, + vec!["Hello".to_string(), "World".to_string()] + ); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/newtype.rs b/third_party/cargo/vendor/darling-0.10.2/tests/newtype.rs new file mode 100644 index 0000000..5219d9a --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/newtype.rs @@ -0,0 +1,32 @@ +//! A newtype struct should be able to derive `FromMeta` if its member implements it. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Debug, FromMeta, PartialEq, Eq)] +struct Lorem(bool); + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(newtype))] +struct DemoContainer { + lorem: Lorem, +} + +#[test] +fn generated() { + let di = parse_quote! { + #[derive(Baz)] + #[newtype(lorem = false)] + pub struct Foo; + }; + + let c = DemoContainer::from_derive_input(&di).unwrap(); + + assert_eq!(c.lorem, Lorem(false)); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/skip.rs b/third_party/cargo/vendor/darling-0.10.2/tests/skip.rs new file mode 100644 index 0000000..b4e0f64 --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/skip.rs @@ -0,0 +1,52 @@ +//! Test that skipped fields are not read into structs when they appear in input. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Debug, PartialEq, Eq, FromDeriveInput)] +#[darling(attributes(skip_test))] +pub struct Lorem { + ipsum: String, + + #[darling(skip)] + dolor: u8, +} + +/// Verify variant-level and field-level skip work correctly for enums. +#[derive(Debug, FromMeta)] +pub enum Sit { + Amet(bool), + + #[darling(skip)] + Foo { + hello: bool, + }, + + Bar { + hello: bool, + #[darling(skip)] + world: u8, + }, +} + +#[test] +fn verify_skipped_field_not_required() { + let di = parse_quote! { + #[skip_test(ipsum = "Hello")] + struct Baz; + }; + + assert_eq!( + Lorem::from_derive_input(&di).unwrap(), + Lorem { + ipsum: "Hello".to_string(), + dolor: 0, + } + ); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/split_declaration.rs b/third_party/cargo/vendor/darling-0.10.2/tests/split_declaration.rs new file mode 100644 index 0000000..23d458d --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/split_declaration.rs @@ -0,0 +1,78 @@ +//! When input is split across multiple attributes on one element, +//! darling should collapse that into one struct. + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use std::string::ToString; + +use darling::{Error, FromDeriveInput}; + +#[derive(Debug, FromDeriveInput, PartialEq, Eq)] +#[darling(attributes(split))] +struct Lorem { + foo: String, + bar: bool, +} + +#[test] +fn split_attributes_accrue_to_instance() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(bar)] + pub struct Foo; + }; + + let parsed = Lorem::from_derive_input(&di).unwrap(); + assert_eq!( + parsed, + Lorem { + foo: "Hello".to_string(), + bar: true, + } + ); +} + +#[test] +fn duplicates_across_split_attrs_error() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(foo = "World", bar)] + pub struct Foo; + }; + + let pr = Lorem::from_derive_input(&di).unwrap_err(); + assert!(pr.has_span()); + assert_eq!( + pr.to_string(), + Error::duplicate_field("foo").to_string() + ); +} + +#[test] +fn multiple_errors_accrue_to_instance() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(foo = "World")] + pub struct Foo; + }; + + let pr = Lorem::from_derive_input(&di); + let err: Error = pr.unwrap_err(); + assert_eq!(2, err.len()); + let mut errs = err.into_iter().peekable(); + assert_eq!( + errs.peek().unwrap().to_string(), + Error::duplicate_field("foo").to_string() + ); + assert!(errs.next().unwrap().has_span()); + assert_eq!( + errs.next().unwrap().to_string(), + Error::missing_field("bar").to_string() + ); + assert!(errs.next().is_none()); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/suggestions.rs b/third_party/cargo/vendor/darling-0.10.2/tests/suggestions.rs new file mode 100644 index 0000000..3499e9e --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/suggestions.rs @@ -0,0 +1,34 @@ +#![cfg(feature = "suggestions")] + +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::FromDeriveInput; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(suggest))] +struct Lorem { + ipsum: String, + dolor: Dolor, +} + +#[derive(Debug, FromMeta)] +struct Dolor { + sit: bool, +} + +#[test] +fn suggest_dolor() { + let input: syn::DeriveInput = parse_quote! { + #[suggest(ipsum = "Hello", dolorr(sit))] + pub struct Foo; + }; + + let result = Lorem::from_derive_input(&input).unwrap_err(); + assert_eq!(2, result.len()); + assert!(format!("{}", result).contains("Did you mean")); +} diff --git a/third_party/cargo/vendor/darling-0.10.2/tests/supports.rs b/third_party/cargo/vendor/darling-0.10.2/tests/supports.rs new file mode 100644 index 0000000..ead3bad --- /dev/null +++ b/third_party/cargo/vendor/darling-0.10.2/tests/supports.rs @@ -0,0 +1,85 @@ +#[macro_use] +extern crate darling; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; + +use darling::ast; +use darling::FromDeriveInput; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_variants), supports(enum_any))] +pub struct Container { + data: ast::Data, +} + +#[derive(Default, Debug, FromVariant)] +#[darling(default, attributes(from_variants), supports(newtype, unit))] +pub struct Variant { + into: Option, + skip: Option, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_struct), supports(struct_named))] +pub struct StructContainer { + data: ast::Data<(), syn::Field>, +} + +mod source { + use syn::DeriveInput; + + pub fn newtype_enum() -> DeriveInput { + parse_quote!{ + enum Hello { + World(bool), + String(String), + } + } + } + + pub fn named_field_enum() -> DeriveInput { + parse_quote! { + enum Hello { + Foo(u16), + World { + name: String + }, + } + } + } + + pub fn named_struct() -> DeriveInput { + parse_quote! { + struct Hello { + world: bool, + } + } + } + + pub fn tuple_struct() -> DeriveInput { + parse_quote! { struct Hello(String, bool); } + } +} + +#[test] +fn enum_newtype_or_unit() { + // Should pass + Container::from_derive_input(&source::newtype_enum()).unwrap(); + + // Should error + Container::from_derive_input(&source::named_field_enum()).unwrap_err(); + Container::from_derive_input(&source::named_struct()).unwrap_err(); +} + +#[test] +fn struct_named() { + // Should pass + StructContainer::from_derive_input(&source::named_struct()).unwrap(); + + // Should fail + StructContainer::from_derive_input(&source::tuple_struct()).unwrap_err(); + StructContainer::from_derive_input(&source::named_field_enum()).unwrap_err(); + StructContainer::from_derive_input(&source::newtype_enum()).unwrap_err(); +} diff --git a/third_party/cargo/vendor/darling_core-0.10.2/.cargo-checksum.json b/third_party/cargo/vendor/darling_core-0.10.2/.cargo-checksum.json new file mode 100644 index 0000000..89a000b --- /dev/null +++ b/third_party/cargo/vendor/darling_core-0.10.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"06fd4ad0f31c8121174fa62523ebb53360675d00d03fb58433b924edc4de31da","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/ast/data.rs":"73a6b7a679011135dfee25af462163b3fe3f3effdf028c440aa6e3e4b5ff079f","src/ast/generics.rs":"3bdfe1abdbee64f5aaa9b189dc5c58e222568f196ed206e9d6d91ea5f29673e7","src/ast/mod.rs":"58a58eeb1db7682e5994732cc8eb04088f6ca662805460ef443cf089e5c24e2c","src/codegen/attr_extractor.rs":"d49605dbea8e95d64a9859a8beef5cf678390ffc5ba76ec77d69913f650ba974","src/codegen/default_expr.rs":"60f23b77ddf80da70ec92fd0d8cb5a97143535df85eafa0e47943ac797ec46d2","src/codegen/error.rs":"1a415136f93adde7458e39cab91413adc9a64243b718c7b74fdeba748959b5af","src/codegen/field.rs":"82104df8f3e733b23764fd6683e60d24ce62912b8b29a22dadbbc55d6a42f158","src/codegen/from_derive_impl.rs":"7cc03ffcc65e8e06dbf9d469502dc4ddd8772a2177dbf6404ad32d306379f777","src/codegen/from_field.rs":"a77abdb024b9a884dcdfda758ab072f26d5fae12eb67a3deb3dc47c6be2f2390","src/codegen/from_meta_impl.rs":"8fc08e65736efaf82b7aa2ce7e20c1a4235a94840353b860d6e782606c92ce18","src/codegen/from_type_param.rs":"c9cdb902d72f2ec047aeaa5217c2cda551d6cfc570f51ae4420907d6b398d9e7","src/codegen/from_variant_impl.rs":"1b44e10d8a0c43b1dcb7d66d1ced74ffab7f7beaa680031c11cfd4ab1abb39bf","src/codegen/mod.rs":"2dc3ee7f18177b2ef9c27c4f0cabc5bbd49f970abdba28a0539d81c70d81b6e2","src/codegen/outer_from_impl.rs":"41f5b6b4fb9185f88eaab3fbeed8b07e5791d04f265ee3c77e874a869fac7e1a","src/codegen/trait_impl.rs":"94c6f8a190ab2957ddae55745184e056ec5e43e9c552f492a3cb2f387dfb4a6a","src/codegen/variant.rs":"69ee861a63e31feb158611e93d0a355fdd94d6c8f3adc6c550864b7f5906d0ba","src/codegen/variant_data.rs":"bf17078e1bfeb35fae88b6ba124d730a27028ab75a422b247bbe09022c5f84d1","src/derive.rs":"89180c13798b61510a6d266781e065114b75ca0be27e172a24656347b9baf1d3","src/error/kind.rs":"877f025ff72839ede46b8c7460331dac32ec56a7539816820179110381f8d0fb","src/error/mod.rs":"a440321a7d7d76ecdbd100a8a4ac94d231fdf4e58a8758d09c115d6d7e297601","src/from_derive_input.rs":"b2a04fefa4e14684061c819387ea0384297c67c7f50d5d0959aa69ab19075e76","src/from_field.rs":"f667924422ab4ab8d8b16ebfd42f61e74864cfaa80e96b49de5d1e1287e3d1d3","src/from_generic_param.rs":"49c5a8335eb0a9010998c5600c95c89440f7febe03265afb625d818dbc883d92","src/from_generics.rs":"7285b0fd213507e87c1da413cd1bc9eeada485d4a8f9d19630848d02a4d41c4a","src/from_meta.rs":"11cd84155ab7ac2f20eb5eb6b297be3606871bf5ee10fa529cbb6e370fe9ab68","src/from_type_param.rs":"9b611f276871002ade78146266fde3b6f9101b360082681a2fa2dafc16431f84","src/from_variant.rs":"70a23b5b4cb93c7e5a498fe9d16420b9b93bd69c1376d7703bc7cefd9417d159","src/lib.rs":"337ce983fd49548c60bc0d8662f6d279daec1964c79b123453340158d55d39ab","src/macros_private.rs":"ef249cd9ca593aac423b4242df1c39c31610438da094c21562d74a7e5823c700","src/macros_public.rs":"3ed7eb99f309d9cd600d3a09ff4dcf5cc5d787fb49e8e5ead6bb00e31e5e6793","src/options/core.rs":"02659124b387437daf3b7d6c841a07478dc39a5a626e8ac4b7703e48c6675f6d","src/options/forward_attrs.rs":"a8bb729d8096dd467f23d55c5b4f09e1b8f329181b7d63c75b10fb51518277fd","src/options/from_derive.rs":"e3e13549d327169a64e831612c370662d09465e11690a3e8a6d029591dba3c8b","src/options/from_field.rs":"67f338df3ffc270b3baf08b35cbe985802a65c1360c4e540cc5b937f6f08f915","src/options/from_meta.rs":"81a2ae765d390f64fbcbb1d30d40e895d77f8cd4f4c5f7167b1eacb48e066195","src/options/from_type_param.rs":"d3c8add6c8f5f7ee3d4a487c53e1f85002a2da43b943c03d4ce856fa6e7c8453","src/options/from_variant.rs":"6b2d0b37c9f66ff59b2ac74c51bc7c968a44c2f4812baf428ed2f6801a474704","src/options/input_field.rs":"6e09c3432c63130a7def5cd1c4ba2d9ae2f692e58f82224e96f1212f09d2adb5","src/options/input_variant.rs":"94050b9185838296b7eb6ffacf41472cbff63461162b0005ca07c9a792c749ac","src/options/mod.rs":"8fe5c94c3999d210cb024c6f6b181da92a0cc1a4a862e5d46ec49904c6692e11","src/options/outer_from.rs":"648e3005f19b38299284df954b371fba9cea2fab39a6cfd6b54b5437b4200599","src/options/shape.rs":"03ca937d0c158e96337731517b8cfbc839f536e691f2f31713222bd228b49e07","src/usage/generics_ext.rs":"340774fe43033680e6b494c76dd4f558ada7ca4f09e91f9e4d076f125a729fc2","src/usage/ident_set.rs":"30edb2f0a599284967e3c6b579da31e5f9b15f3dd67bc9a82d6335eb44133df0","src/usage/lifetimes.rs":"35546bd524c38cbae2366e59ac2d836fe09af8e59aa99c7992d1e4d725364db7","src/usage/mod.rs":"e49adadfa8ffed27299d5bbf3c33e68e2c8c7411f89aef655f77e158be9dd642","src/usage/options.rs":"0491c995aad0d55783b24cce8a4e40f0f4435988c54ce2ded34763ac9b199fcf","src/usage/type_params.rs":"c46323838a5e1e87a1a75878314a8b1217e8d63d27a5067961c3b908842d248b","src/util/ident_string.rs":"2b7fdbe9664c2e306114ffa830fde9710d849a0240029636cbb244457795b13f","src/util/ignored.rs":"7c979fbef880498ff64efda7396e759d80bf77fb1c7df0313bed8e533a16c0e0","src/util/mod.rs":"9d8fef190513b6ab675a6ea3cf7e2841d2204fd38d8d55b10cc915d583491982","src/util/over_ride.rs":"5750d284d46c6a51522e908b642c8f09cd6e48c91fd25077f24ce75989525560","src/util/path_list.rs":"4d14eef07b6e3a3e69a539c49b3f25d477e79bd55594cd7324fda3b86784b0f5","src/util/spanned_value.rs":"3938cfc5169237cde1f19d65b653e1da8699663d1abfcf005359d48bbcee7d0b","src/util/with_original.rs":"a545b38ba9d624fdc939eb844f001b7fc4102717b1d3683b4cbd0aae00fa7ef2"},"package":"f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"} \ No newline at end of file diff --git a/third_party/cargo/vendor/darling_core-0.10.2/BUILD.bazel b/third_party/cargo/vendor/darling_core-0.10.2/BUILD.bazel new file mode 100644 index 0000000..54de54e --- /dev/null +++ b/third_party/cargo/vendor/darling_core-0.10.2/BUILD.bazel @@ -0,0 +1,61 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT" +]) + +# Generated Targets + +rust_library( + name = "darling_core", + srcs = glob(["**/*.rs"]), + crate_features = [ + "strsim", + "suggestions", + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2015", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "0.10.2", + # buildifier: leave-alone + deps = [ + "//third_party/cargo/vendor/fnv-1.0.7:fnv", + "//third_party/cargo/vendor/ident_case-1.0.1:ident_case", + "//third_party/cargo/vendor/proc-macro2-1.0.24:proc_macro2", + "//third_party/cargo/vendor/quote-1.0.8:quote", + "//third_party/cargo/vendor/strsim-0.9.3:strsim", + "//third_party/cargo/vendor/syn-1.0.58:syn", + ], +) diff --git a/third_party/cargo/vendor/darling_core-0.10.2/Cargo.toml b/third_party/cargo/vendor/darling_core-0.10.2/Cargo.toml new file mode 100644 index 0000000..55231d6 --- /dev/null +++ b/third_party/cargo/vendor/darling_core-0.10.2/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "darling_core" +version = "0.10.2" +authors = ["Ted Driggs "] +description = "Helper crate for proc-macro library for reading attributes into structs when\nimplementing custom derives. Use https://crates.io/crates/darling in your code.\n" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" +[dependencies.fnv] +version = "1.0.6" + +[dependencies.ident_case] +version = "1.0.0" + +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.strsim] +version = "0.9.0" +optional = true + +[dependencies.syn] +version = "1.0.1" +features = ["full", "extra-traits"] + +[features] +diagnostics = [] +suggestions = ["strsim"] diff --git a/third_party/cargo/vendor/darling_core-0.10.2/LICENSE b/third_party/cargo/vendor/darling_core-0.10.2/LICENSE new file mode 100644 index 0000000..0b48ead --- /dev/null +++ b/third_party/cargo/vendor/darling_core-0.10.2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/cargo/vendor/darling_core-0.10.2/src/ast/data.rs b/third_party/cargo/vendor/darling_core-0.10.2/src/ast/data.rs new file mode 100644 index 0000000..a0c765c --- /dev/null +++ b/third_party/cargo/vendor/darling_core-0.10.2/src/ast/data.rs @@ -0,0 +1,360 @@ +use std::{slice, vec}; + +use syn; + +use usage::{ + self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams, +}; +use {Error, FromField, FromVariant, Result}; + +/// A struct or enum body. +/// +/// `V` is the type which receives any encountered variants, and `F` receives struct fields. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Data { + Enum(Vec), + Struct(Fields), +} + +impl Data { + /// Creates an empty body of the same shape as the passed-in body. + pub fn empty_from(src: &syn::Data) -> Self { + match *src { + syn::Data::Enum(_) => Data::Enum(vec![]), + syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)), + syn::Data::Union(_) => unreachable!(), + } + } + + /// Creates a new `Data<&'a V, &'a F>` instance from `Data`. + pub fn as_ref<'a>(&'a self) -> Data<&'a V, &'a F> { + match *self { + Data::Enum(ref variants) => Data::Enum(variants.iter().collect()), + Data::Struct(ref data) => Data::Struct(data.as_ref()), + } + } + + /// Applies a function `V -> U` on enum variants, if this is an enum. + pub fn map_enum_variants(self, map: T) -> Data + where + T: FnMut(V) -> U, + { + match self { + Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()), + Data::Struct(f) => Data::Struct(f), + } + } + + /// Applies a function `F -> U` on struct fields, if this is a struct. + pub fn map_struct_fields(self, map: T) -> Data + where + T: FnMut(F) -> U, + { + match self { + Data::Enum(v) => Data::Enum(v), + Data::Struct(f) => Data::Struct(f.map(map)), + } + } + + /// Applies a function to the `Fields` if this is a struct. + pub fn map_struct(self, mut map: T) -> Data + where + T: FnMut(Fields) -> Fields, + { + match self { + Data::Enum(v) => Data::Enum(v), + Data::Struct(f) => Data::Struct(map(f)), + } + } + + /// Consumes the `Data`, returning `Fields` if it was a struct. + pub fn take_struct(self) -> Option> { + match self { + Data::Enum(_) => None, + Data::Struct(f) => Some(f), + } + } + + /// Consumes the `Data`, returning `Vec` if it was an enum. + pub fn take_enum(self) -> Option> { + match self { + Data::Enum(v) => Some(v), + Data::Struct(_) => None, + } + } + + /// Returns `true` if this instance is `Data::Enum`. + pub fn is_enum(&self) -> bool { + match *self { + Data::Enum(_) => true, + Data::Struct(_) => false, + } + } + + /// Returns `true` if this instance is `Data::Struct`. + pub fn is_struct(&self) -> bool { + !self.is_enum() + } +} + +impl Data { + /// Attempt to convert from a `syn::Data` instance. + pub fn try_from(body: &syn::Data) -> Result { + match *body { + syn::Data::Enum(ref data) => { + let mut items = Vec::with_capacity(data.variants.len()); + let mut errors = Vec::new(); + for v_result in data.variants.iter().map(FromVariant::from_variant) { + match v_result { + Ok(val) => items.push(val), + Err(err) => errors.push(err), + } + } + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(Data::Enum(items)) + } + } + syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)), + syn::Data::Union(_) => unreachable!(), + } + } +} + +impl UsesTypeParams for Data { + fn uses_type_params<'a>( + &self, + options: &usage::Options, + type_set: &'a IdentSet, + ) -> IdentRefSet<'a> { + match *self { + Data::Struct(ref v) => v.uses_type_params(options, type_set), + Data::Enum(ref v) => v.uses_type_params(options, type_set), + } + } +} + +impl UsesLifetimes for Data { + fn uses_lifetimes<'a>( + &self, + options: &usage::Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes), + Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +/// Equivalent to `syn::Fields`, but replaces the AST element with a generic. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Fields { + pub style: Style, + pub fields: Vec, +} + +impl Fields { + pub fn empty_from(vd: &syn::Fields) -> Self { + Fields { + style: vd.into(), + fields: Vec::new(), + } + } + + /// Splits the `Fields` into its style and fields for further processing. + /// Returns an empty `Vec` for `Unit` data. + pub fn split(self) -> (Style, Vec) { + (self.style, self.fields) + } + + /// Returns true if this variant's data makes it a newtype. + pub fn is_newtype(&self) -> bool { + self.style == Style::Tuple && self.len() == 1 + } + + pub fn is_unit(&self) -> bool { + self.style.is_unit() + } + + pub fn is_tuple(&self) -> bool { + self.style.is_tuple() + } + + pub fn is_struct(&self) -> bool { + self.style.is_struct() + } + + pub fn as_ref<'a>(&'a self) -> Fields<&'a T> { + Fields { + style: self.style, + fields: self.fields.iter().collect(), + } + } + + pub fn map(self, map: F) -> Fields + where + F: FnMut(T) -> U, + { + Fields { + style: self.style, + fields: self.fields.into_iter().map(map).collect(), + } + } + + pub fn iter(&self) -> slice::Iter { + self.fields.iter() + } + + /// Returns the number of fields in the structure. + pub fn len(&self) -> usize { + self.fields.len() + } + + /// Returns `true` if the `Fields` contains no fields. + pub fn is_empty(&self) -> bool { + self.fields.is_empty() + } +} + +impl Fields { + pub fn try_from(fields: &syn::Fields) -> Result { + let (items, errors) = match *fields { + syn::Fields::Named(ref fields) => { + let mut items = Vec::with_capacity(fields.named.len()); + let mut errors = Vec::new(); + + for field in &fields.named { + match FromField::from_field(field) { + Ok(val) => items.push(val), + Err(err) => errors.push(if let Some(ref ident) = field.ident { + err.at(ident) + } else { + err + }), + } + } + + (items, errors) + } + syn::Fields::Unnamed(ref fields) => { + let mut items = Vec::with_capacity(fields.unnamed.len()); + let mut errors = Vec::new(); + + for field in &fields.unnamed { + match FromField::from_field(field) { + Ok(val) => items.push(val), + Err(err) => errors.push(if let Some(ref ident) = field.ident { + err.at(ident) + } else { + err + }), + } + } + + (items, errors) + } + syn::Fields::Unit => (vec![], vec![]), + }; + + if !errors.is_empty() { + Err(Error::multiple(errors)) + } else { + Ok(Fields { + style: fields.into(), + fields: items, + }) + } + } +} + +impl IntoIterator for Fields { + type Item = T; + type IntoIter = vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.fields.into_iter() + } +} + +impl From

(&mut self, p: P) -> &mut Build + where + P: IntoIterator, + P::Item: AsRef, + { + for file in p.into_iter() { + self.file(file); + } + self + } + + /// Set C++ support. + /// + /// The other `cpp_*` options will only become active if this is set to + /// `true`. + pub fn cpp(&mut self, cpp: bool) -> &mut Build { + self.cpp = cpp; + self + } + + /// Set CUDA C++ support. + /// + /// Enabling CUDA will pass the detected C/C++ toolchain as an argument to + /// the CUDA compiler, NVCC. NVCC itself accepts some limited GNU-like args; + /// any other arguments for the C/C++ toolchain will be redirected using + /// "-Xcompiler" flags. + /// + /// If enabled, this also implicitly enables C++ support. + pub fn cuda(&mut self, cuda: bool) -> &mut Build { + self.cuda = cuda; + if cuda { + self.cpp = true; + } + self + } + + /// Set warnings into errors flag. + /// + /// Disabled by default. + /// + /// Warning: turning warnings into errors only make sense + /// if you are a developer of the crate using cc-rs. + /// Some warnings only appear on some architecture or + /// specific version of the compiler. Any user of this crate, + /// or any other crate depending on it, could fail during + /// compile time. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings_into_errors(true) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings_into_errors(&mut self, warnings_into_errors: bool) -> &mut Build { + self.warnings_into_errors = warnings_into_errors; + self + } + + /// Set warnings flags. + /// + /// Adds some flags: + /// - "-Wall" for MSVC. + /// - "-Wall", "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings(&mut self, warnings: bool) -> &mut Build { + self.warnings = Some(warnings); + self.extra_warnings = Some(warnings); + self + } + + /// Set extra warnings flags. + /// + /// Adds some flags: + /// - nothing for MSVC. + /// - "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// // Disables -Wextra, -Wall remains enabled: + /// cc::Build::new() + /// .file("src/foo.c") + /// .extra_warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn extra_warnings(&mut self, warnings: bool) -> &mut Build { + self.extra_warnings = Some(warnings); + self + } + + /// Set the standard library to link against when compiling with C++ + /// support. + /// + /// See [`get_cpp_link_stdlib`](cc::Build::get_cpp_link_stdlib) documentation + /// for the default value. + /// If the `CXXSTDLIB` environment variable is set, its value will + /// override the default value, but not the value explicitly set by calling + /// this function. + /// + /// A value of `None` indicates that no automatic linking should happen, + /// otherwise cargo will link against the specified library. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// - `c++_shared` or `c++_static` for Android + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .cpp_link_stdlib("stdc++") + /// .compile("libfoo.so"); + /// ``` + pub fn cpp_link_stdlib<'a, V: Into>>( + &mut self, + cpp_link_stdlib: V, + ) -> &mut Build { + self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); + self + } + + /// Force the C++ compiler to use the specified standard library. + /// + /// Setting this option will automatically set `cpp_link_stdlib` to the same + /// value. + /// + /// The default value of this option is always `None`. + /// + /// This option has no effect when compiling for a Visual Studio based + /// target. + /// + /// This option sets the `-stdlib` flag, which is only supported by some + /// compilers (clang, icc) but not by others (gcc). The library will not + /// detect which compiler is used, as such it is the responsibility of the + /// caller to ensure that this option is only used in conjuction with a + /// compiler which supports the `-stdlib` flag. + /// + /// A value of `None` indicates that no specific C++ standard library should + /// be used, otherwise `-stdlib` is added to the compile invocation. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .cpp_set_stdlib("c++") + /// .compile("libfoo.a"); + /// ``` + pub fn cpp_set_stdlib<'a, V: Into>>( + &mut self, + cpp_set_stdlib: V, + ) -> &mut Build { + let cpp_set_stdlib = cpp_set_stdlib.into(); + self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); + self.cpp_link_stdlib(cpp_set_stdlib); + self + } + + /// Configures the target this configuration will be compiling for. + /// + /// This option is automatically scraped from the `TARGET` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .target("aarch64-linux-android") + /// .compile("foo"); + /// ``` + pub fn target(&mut self, target: &str) -> &mut Build { + self.target = Some(target.to_string()); + self + } + + /// Configures the host assumed by this configuration. + /// + /// This option is automatically scraped from the `HOST` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .host("arm-linux-gnueabihf") + /// .compile("foo"); + /// ``` + pub fn host(&mut self, host: &str) -> &mut Build { + self.host = Some(host.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level(&mut self, opt_level: u32) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures whether the compiler will emit debug information when + /// generating object files. + /// + /// This option is automatically scraped from the `DEBUG` environment + /// variable by build scripts, so it's not required to call this function. + pub fn debug(&mut self, debug: bool) -> &mut Build { + self.debug = Some(debug); + self + } + + /// Configures whether the compiler will emit instructions to store + /// frame pointers during codegen. + /// + /// This option is automatically enabled when debug information is emitted. + /// Otherwise the target platform compiler's default will be used. + /// You can use this option to force a specific setting. + pub fn force_frame_pointer(&mut self, force: bool) -> &mut Build { + self.force_frame_pointer = Some(force); + self + } + + /// Configures the output directory where all object files and static + /// libraries will be located. + /// + /// This option is automatically scraped from the `OUT_DIR` environment + /// variable by build scripts, so it's not required to call this function. + pub fn out_dir>(&mut self, out_dir: P) -> &mut Build { + self.out_dir = Some(out_dir.as_ref().to_owned()); + self + } + + /// Configures the compiler to be used to produce output. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn compiler>(&mut self, compiler: P) -> &mut Build { + self.compiler = Some(compiler.as_ref().to_owned()); + self + } + + /// Configures the tool used to assemble archives. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn archiver>(&mut self, archiver: P) -> &mut Build { + self.archiver = Some(archiver.as_ref().to_owned()); + self + } + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + /// + /// The emitted metadata is: + /// + /// - `rustc-link-lib=static=`*compiled lib* + /// - `rustc-link-search=native=`*target folder* + /// - When target is MSVC, the ATL-MFC libs are added via `rustc-link-search=native=` + /// - When C++ is enabled, the C++ stdlib is added via `rustc-link-lib` + /// + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { + self.cargo_metadata = cargo_metadata; + self + } + + /// Configures whether the compiler will emit position independent code. + /// + /// This option defaults to `false` for `windows-gnu` and bare metal targets and + /// to `true` for all other targets. + pub fn pic(&mut self, pic: bool) -> &mut Build { + self.pic = Some(pic); + self + } + + /// Configures whether the Procedure Linkage Table is used for indirect + /// calls into shared libraries. + /// + /// The PLT is used to provide features like lazy binding, but introduces + /// a small performance loss due to extra pointer indirection. Setting + /// `use_plt` to `false` can provide a small performance increase. + /// + /// Note that skipping the PLT requires a recent version of GCC/Clang. + /// + /// This only applies to ELF targets. It has no effect on other platforms. + pub fn use_plt(&mut self, use_plt: bool) -> &mut Build { + self.use_plt = Some(use_plt); + self + } + + /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. + /// + /// This option defaults to `false`, and affect only msvc targets. + pub fn static_crt(&mut self, static_crt: bool) -> &mut Build { + self.static_crt = Some(static_crt); + self + } + + #[doc(hidden)] + pub fn __set_env(&mut self, a: A, b: B) -> &mut Build + where + A: AsRef, + B: AsRef, + { + self.env + .push((a.as_ref().to_owned(), b.as_ref().to_owned())); + self + } + + /// Run the compiler, generating the file `output` + /// + /// This will return a result instead of panicing; see compile() for the complete description. + pub fn try_compile(&self, output: &str) -> Result<(), Error> { + let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { + (&output[3..output.len() - 2], output.to_owned()) + } else { + let mut gnu = String::with_capacity(5 + output.len()); + gnu.push_str("lib"); + gnu.push_str(&output); + gnu.push_str(".a"); + (output, gnu) + }; + let dst = self.get_out_dir()?; + + let mut objects = Vec::new(); + for file in self.files.iter() { + let obj = dst.join(file).with_extension("o"); + let obj = if !obj.starts_with(&dst) { + dst.join(obj.file_name().ok_or_else(|| { + Error::new(ErrorKind::IOError, "Getting object file details failed.") + })?) + } else { + obj + }; + + match obj.parent() { + Some(s) => fs::create_dir_all(s)?, + None => { + return Err(Error::new( + ErrorKind::IOError, + "Getting object file details failed.", + )); + } + }; + + objects.push(Object::new(file.to_path_buf(), obj)); + } + self.compile_objects(&objects)?; + self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?; + + if self.get_target()?.contains("msvc") { + let compiler = self.get_base_compiler()?; + let atlmfc_lib = compiler + .env() + .iter() + .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) + .and_then(|&(_, ref lib_paths)| { + env::split_paths(lib_paths).find(|path| { + let sub = Path::new("atlmfc/lib"); + path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) + }) + }); + + if let Some(atlmfc_lib) = atlmfc_lib { + self.print(&format!( + "cargo:rustc-link-search=native={}", + atlmfc_lib.display() + )); + } + } + + self.print(&format!("cargo:rustc-link-lib=static={}", lib_name)); + self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); + + // Add specific C++ libraries, if enabled. + if self.cpp { + if let Some(stdlib) = self.get_cpp_link_stdlib()? { + self.print(&format!("cargo:rustc-link-lib={}", stdlib)); + } + } + + Ok(()) + } + + /// Run the compiler, generating the file `output` + /// + /// The name `output` should be the name of the library. For backwards compatibility, + /// the `output` may start with `lib` and end with `.a`. The Rust compiler will create + /// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix, + /// ending with `.lib`. + /// + /// # Panics + /// + /// Panics if `output` is not formatted correctly or if one of the underlying + /// compiler commands fails. It can also panic if it fails reading file names + /// or creating directories. + pub fn compile(&self, output: &str) { + if let Err(e) = self.try_compile(output) { + fail(&e.message); + } + } + + #[cfg(feature = "parallel")] + fn compile_objects<'me>(&'me self, objs: &[Object]) -> Result<(), Error> { + use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; + use std::sync::Once; + + // Limit our parallelism globally with a jobserver. Start off by + // releasing our own token for this process so we can have a bit of an + // easier to write loop below. If this fails, though, then we're likely + // on Windows with the main implicit token, so we just have a bit extra + // parallelism for a bit and don't reacquire later. + let server = jobserver(); + let reacquire = server.release_raw().is_ok(); + + // When compiling objects in parallel we do a few dirty tricks to speed + // things up: + // + // * First is that we use the `jobserver` crate to limit the parallelism + // of this build script. The `jobserver` crate will use a jobserver + // configured by Cargo for build scripts to ensure that parallelism is + // coordinated across C compilations and Rust compilations. Before we + // compile anything we make sure to wait until we acquire a token. + // + // Note that this jobserver is cached globally so we only used one per + // process and only worry about creating it once. + // + // * Next we use a raw `thread::spawn` per thread to actually compile + // objects in parallel. We only actually spawn a thread after we've + // acquired a token to perform some work + // + // * Finally though we want to keep the dependencies of this crate + // pretty light, so we avoid using a safe abstraction like `rayon` and + // instead rely on some bits of `unsafe` code. We know that this stack + // frame persists while everything is compiling so we use all the + // stack-allocated objects without cloning/reallocating. We use a + // transmute to `State` with a `'static` lifetime to persist + // everything we need across the boundary, and the join-on-drop + // semantics of `JoinOnDrop` should ensure that our stack frame is + // alive while threads are alive. + // + // With all that in mind we compile all objects in a loop here, after we + // acquire the appropriate tokens, Once all objects have been compiled + // we join on all the threads and propagate the results of compilation. + // + // Note that as a slight optimization we try to break out as soon as + // possible as soon as any compilation fails to ensure that errors get + // out to the user as fast as possible. + let error = AtomicBool::new(false); + let mut threads = Vec::new(); + for obj in objs { + if error.load(SeqCst) { + break; + } + let token = server.acquire()?; + let state = State { + build: self, + obj, + error: &error, + }; + let state = unsafe { std::mem::transmute::>(state) }; + let thread = thread::spawn(|| { + let state: State<'me> = state; // erase the `'static` lifetime + let result = state.build.compile_object(state.obj); + if result.is_err() { + state.error.store(true, SeqCst); + } + drop(token); // make sure our jobserver token is released after the compile + return result; + }); + threads.push(JoinOnDrop(Some(thread))); + } + + for mut thread in threads { + if let Some(thread) = thread.0.take() { + thread.join().expect("thread should not panic")?; + } + } + + // Reacquire our process's token before we proceed, which we released + // before entering the loop above. + if reacquire { + server.acquire_raw()?; + } + + return Ok(()); + + /// Shared state from the parent thread to the child thread. This + /// package of pointers is temporarily transmuted to a `'static` + /// lifetime to cross the thread boundary and then once the thread is + /// running we erase the `'static` to go back to an anonymous lifetime. + struct State<'a> { + build: &'a Build, + obj: &'a Object, + error: &'a AtomicBool, + } + + /// Returns a suitable `jobserver::Client` used to coordinate + /// parallelism between build scripts. + fn jobserver() -> &'static jobserver::Client { + static INIT: Once = Once::new(); + static mut JOBSERVER: Option = None; + + fn _assert_sync() {} + _assert_sync::(); + + unsafe { + INIT.call_once(|| { + let server = default_jobserver(); + JOBSERVER = Some(server); + }); + JOBSERVER.as_ref().unwrap() + } + } + + unsafe fn default_jobserver() -> jobserver::Client { + // Try to use the environmental jobserver which Cargo typically + // initializes for us... + if let Some(client) = jobserver::Client::from_env() { + return client; + } + + // ... but if that fails for whatever reason select something + // reasonable and crate a new jobserver. Use `NUM_JOBS` if set (it's + // configured by Cargo) and otherwise just fall back to a + // semi-reasonable number. Note that we could use `num_cpus` here + // but it's an extra dependency that will almost never be used, so + // it's generally not too worth it. + let mut parallelism = 4; + if let Ok(amt) = env::var("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + parallelism = amt; + } + } + + // If we create our own jobserver then be sure to reserve one token + // for ourselves. + let client = jobserver::Client::new(parallelism).expect("failed to create jobserver"); + client.acquire_raw().expect("failed to acquire initial"); + return client; + } + + struct JoinOnDrop(Option>>); + + impl Drop for JoinOnDrop { + fn drop(&mut self) { + if let Some(thread) = self.0.take() { + drop(thread.join()); + } + } + } + } + + #[cfg(not(feature = "parallel"))] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + for obj in objs { + self.compile_object(obj)?; + } + Ok(()) + } + + fn compile_object(&self, obj: &Object) -> Result<(), Error> { + let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm"); + let target = self.get_target()?; + let msvc = target.contains("msvc"); + let compiler = self.try_get_compiler()?; + let clang = compiler.family == ToolFamily::Clang; + let (mut cmd, name) = if msvc && is_asm { + self.msvc_macro_assembler()? + } else { + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + ( + cmd, + compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(), + ) + }; + let is_arm = target.contains("aarch64") || target.contains("arm"); + command_add_output_file(&mut cmd, &obj.dst, self.cuda, msvc, clang, is_asm, is_arm); + // armasm and armasm64 don't requrie -c option + if !msvc || !is_asm || !is_arm { + cmd.arg("-c"); + } + cmd.arg(&obj.src); + if cfg!(target_os = "macos") { + self.fix_env_for_apple_os(&mut cmd)?; + } + + run(&mut cmd, &name)?; + Ok(()) + } + + /// This will return a result instead of panicing; see expand() for the complete description. + pub fn try_expand(&self) -> Result, Error> { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd.arg("-E"); + + assert!( + self.files.len() <= 1, + "Expand may only be called for a single file" + ); + + for file in self.files.iter() { + cmd.arg(file); + } + + let name = compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(); + + Ok(run_output(&mut cmd, &name)?) + } + + /// Run the compiler, returning the macro-expanded version of the input files. + /// + /// This is only relevant for C and C++ files. + /// + /// # Panics + /// Panics if more than one file is present in the config, or if compiler + /// path has an invalid file name. + /// + /// # Example + /// ```no_run + /// let out = cc::Build::new().file("src/foo.c").expand(); + /// ``` + pub fn expand(&self) -> Vec { + match self.try_expand() { + Err(e) => fail(&e.message), + Ok(v) => v, + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This function will return a `Tool` which represents the culmination + /// of this configuration at a snapshot in time. The returned compiler can + /// be inspected (e.g. the path, arguments, environment) to forward along to + /// other tools, or the `to_command` method can be used to invoke the + /// compiler itself. + /// + /// This method will take into account all configuration such as debug + /// information, optimization level, include directories, defines, etc. + /// Additionally, the compiler binary in use follows the standard + /// conventions for this path, e.g. looking at the explicitly set compiler, + /// environment variables (a number of which are inspected here), and then + /// falling back to the default configuration. + /// + /// # Panics + /// + /// Panics if an error occurred while determining the architecture. + pub fn get_compiler(&self) -> Tool { + match self.try_get_compiler() { + Ok(tool) => tool, + Err(e) => fail(&e.message), + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This will return a result instead of panicing; see get_compiler() for the complete description. + pub fn try_get_compiler(&self) -> Result { + let opt_level = self.get_opt_level()?; + let target = self.get_target()?; + + let mut cmd = self.get_base_compiler()?; + let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }); + + // Disable default flag generation via `no_default_flags` or environment variable + let no_defaults = self.no_default_flags || self.getenv("CRATE_CC_NO_DEFAULTS").is_some(); + + if !no_defaults { + self.add_default_flags(&mut cmd, &target, &opt_level)?; + } else { + println!("Info: default compiler flags are disabled"); + } + + for arg in envflags { + cmd.push_cc_arg(arg.into()); + } + + for directory in self.include_directories.iter() { + cmd.args.push("-I".into()); + cmd.args.push(directory.into()); + } + + // If warnings and/or extra_warnings haven't been explicitly set, + // then we set them only if the environment doesn't already have + // CFLAGS/CXXFLAGS, since those variables presumably already contain + // the desired set of warnings flags. + + if self + .warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + let wflags = cmd.family.warnings_flags().into(); + cmd.push_cc_arg(wflags); + } + + if self + .extra_warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + if let Some(wflags) = cmd.family.extra_warnings_flags() { + cmd.push_cc_arg(wflags.into()); + } + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + + for flag in self.flags_supported.iter() { + if self.is_flag_supported(flag).unwrap_or(false) { + cmd.push_cc_arg(flag.into()); + } + } + + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.args.push(format!("-D{}={}", key, value).into()); + } else { + cmd.args.push(format!("-D{}", key).into()); + } + } + + if self.warnings_into_errors { + let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); + cmd.push_cc_arg(warnings_to_errors_flag); + } + + Ok(cmd) + } + + fn add_default_flags( + &self, + cmd: &mut Tool, + target: &str, + opt_level: &str, + ) -> Result<(), Error> { + // Non-target flags + // If the flag is not conditioned on target variable, it belongs here :) + match cmd.family { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("-nologo".into()); + + let crt_flag = match self.static_crt { + Some(true) => "-MT", + Some(false) => "-MD", + None => { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + "-MT" + } else { + "-MD" + } + } + }; + cmd.push_cc_arg(crt_flag.into()); + + match &opt_level[..] { + // Msvc uses /O1 to enable all optimizations that minimize code size. + "z" | "s" | "1" => cmd.push_opt_unless_duplicate("-O1".into()), + // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. + "2" | "3" => cmd.push_opt_unless_duplicate("-O2".into()), + _ => {} + } + } + ToolFamily::Gnu | ToolFamily::Clang => { + // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does + // not support '-Oz' + if opt_level == "z" && cmd.family != ToolFamily::Clang { + cmd.push_opt_unless_duplicate("-Os".into()); + } else { + cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); + } + + if cmd.family == ToolFamily::Clang && target.contains("android") { + // For compatibility with code that doesn't use pre-defined `__ANDROID__` macro. + // If compiler used via ndk-build or cmake (officially supported build methods) + // this macros is defined. + // See https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/cmake/android.toolchain.cmake#456 + // https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/core/build-binary.mk#141 + cmd.push_opt_unless_duplicate("-DANDROID".into()); + } + + if !target.contains("-ios") { + cmd.push_cc_arg("-ffunction-sections".into()); + cmd.push_cc_arg("-fdata-sections".into()); + } + // Disable generation of PIC on bare-metal for now: rust-lld doesn't support this yet + if self + .pic + .unwrap_or(!target.contains("windows") && !target.contains("-none-")) + { + cmd.push_cc_arg("-fPIC".into()); + // PLT only applies if code is compiled with PIC support, + // and only for ELF targets. + if target.contains("linux") && !self.use_plt.unwrap_or(true) { + cmd.push_cc_arg("-fno-plt".into()); + } + } + } + } + + if self.get_debug() { + if self.cuda { + // NVCC debug flag + cmd.args.push("-G".into()); + } + let family = cmd.family; + family.add_debug_flags(cmd); + } + + if self.get_force_frame_pointer() { + let family = cmd.family; + family.add_force_frame_pointer(cmd); + } + + // Target flags + match cmd.family { + ToolFamily::Clang => { + if !(target.contains("android") + && android_clang_compiler_uses_target_arg_internally(&cmd.path)) + { + if target.contains("darwin") { + if let Some(arch) = + map_darwin_target_from_rust_to_compiler_architecture(target) + { + cmd.args + .push(format!("--target={}-apple-darwin", arch).into()); + } + } else if target.contains("macabi") { + if let Some(arch) = + map_darwin_target_from_rust_to_compiler_architecture(target) + { + let ios = if arch == "arm64" { "ios" } else { "ios13.0" }; + cmd.args + .push(format!("--target={}-apple-{}-macabi", arch, ios).into()); + } + } else { + cmd.args.push(format!("--target={}", target).into()); + } + } + } + ToolFamily::Msvc { clang_cl } => { + // This is an undocumented flag from MSVC but helps with making + // builds more reproducible by avoiding putting timestamps into + // files. + cmd.push_cc_arg("-Brepro".into()); + + if clang_cl { + if target.contains("x86_64") { + cmd.push_cc_arg("-m64".into()); + } else if target.contains("86") { + cmd.push_cc_arg("-m32".into()); + cmd.push_cc_arg("-arch:IA32".into()); + } else { + cmd.push_cc_arg(format!("--target={}", target).into()); + } + } else { + if target.contains("i586") { + cmd.push_cc_arg("-arch:IA32".into()); + } + } + + // There is a check in corecrt.h that will generate a + // compilation error if + // _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE is + // not defined to 1. The check was added in Windows + // 8 days because only store apps were allowed on ARM. + // This changed with the release of Windows 10 IoT Core. + // The check will be going away in future versions of + // the SDK, but for all released versions of the + // Windows SDK it is required. + if target.contains("arm") || target.contains("thumb") { + cmd.args + .push("-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); + } + } + ToolFamily::Gnu => { + if target.contains("i686") || target.contains("i586") { + cmd.args.push("-m32".into()); + } else if target == "x86_64-unknown-linux-gnux32" { + cmd.args.push("-mx32".into()); + } else if target.contains("x86_64") || target.contains("powerpc64") { + cmd.args.push("-m64".into()); + } + + if target.contains("darwin") { + if let Some(arch) = map_darwin_target_from_rust_to_compiler_architecture(target) + { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + } + } + + if self.static_flag.is_none() { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + cmd.args.push("-static".into()); + } + } + + // armv7 targets get to use armv7 instructions + if (target.starts_with("armv7") || target.starts_with("thumbv7")) + && target.contains("-linux-") + { + cmd.args.push("-march=armv7-a".into()); + } + + // (x86 Android doesn't say "eabi") + if target.contains("-androideabi") && target.contains("v7") { + // -march=armv7-a handled above + cmd.args.push("-mthumb".into()); + if !target.contains("neon") { + // On android we can guarantee some extra float instructions + // (specified in the android spec online) + // NEON guarantees even more; see below. + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + cmd.args.push("-mfloat-abi=softfp".into()); + } + + if target.contains("neon") { + cmd.args.push("-mfpu=neon-vfpv4".into()); + } + + if target.starts_with("armv4t-unknown-linux-") { + cmd.args.push("-march=armv4t".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + if target.starts_with("armv5te-unknown-linux-") { + cmd.args.push("-march=armv5te".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + // For us arm == armv6 by default + if target.starts_with("arm-unknown-linux-") { + cmd.args.push("-march=armv6".into()); + cmd.args.push("-marm".into()); + if target.ends_with("hf") { + cmd.args.push("-mfpu=vfp".into()); + } else { + cmd.args.push("-mfloat-abi=soft".into()); + } + } + + // We can guarantee some settings for FRC + if target.starts_with("arm-frc-") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mcpu=cortex-a9".into()); + cmd.args.push("-mfpu=vfpv3".into()); + cmd.args.push("-mfloat-abi=softfp".into()); + cmd.args.push("-marm".into()); + } + + // Turn codegen down on i586 to avoid some instructions. + if target.starts_with("i586-unknown-linux-") { + cmd.args.push("-march=pentium".into()); + } + + // Set codegen level for i686 correctly + if target.starts_with("i686-unknown-linux-") { + cmd.args.push("-march=i686".into()); + } + + // Looks like `musl-gcc` makes is hard for `-m32` to make its way + // all the way to the linker, so we need to actually instruct the + // linker that we're generating 32-bit executables as well. This'll + // typically only be used for build scripts which transitively use + // these flags that try to compile executables. + if target == "i686-unknown-linux-musl" || target == "i586-unknown-linux-musl" { + cmd.args.push("-Wl,-melf_i386".into()); + } + + if target.starts_with("thumb") { + cmd.args.push("-mthumb".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfloat-abi=hard".into()) + } + } + if target.starts_with("thumbv6m") { + cmd.args.push("-march=armv6s-m".into()); + } + if target.starts_with("thumbv7em") { + cmd.args.push("-march=armv7e-m".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv4-sp-d16".into()) + } + } + if target.starts_with("thumbv7m") { + cmd.args.push("-march=armv7-m".into()); + } + if target.starts_with("thumbv8m.base") { + cmd.args.push("-march=armv8-m.base".into()); + } + if target.starts_with("thumbv8m.main") { + cmd.args.push("-march=armv8-m.main".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv5-sp-d16".into()) + } + } + if target.starts_with("armebv7r") | target.starts_with("armv7r") { + if target.starts_with("armeb") { + cmd.args.push("-mbig-endian".into()); + } else { + cmd.args.push("-mlittle-endian".into()); + } + + // ARM mode + cmd.args.push("-marm".into()); + + // R Profile + cmd.args.push("-march=armv7-r".into()); + + if target.ends_with("eabihf") { + // Calling convention + cmd.args.push("-mfloat-abi=hard".into()); + + // lowest common denominator FPU + // (see Cortex-R4 technical reference manual) + cmd.args.push("-mfpu=vfpv3-d16".into()) + } else { + // Calling convention + cmd.args.push("-mfloat-abi=soft".into()); + } + } + if target.starts_with("armv7a") { + cmd.args.push("-march=armv7-a".into()); + + if target.ends_with("eabihf") { + // lowest common denominator FPU + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + } + if target.starts_with("riscv32") || target.starts_with("riscv64") { + // get the 32i/32imac/32imc/64gc/64imac/... part + let mut parts = target.split('-'); + if let Some(arch) = parts.next() { + let arch = &arch[5..]; + cmd.args.push(("-march=rv".to_owned() + arch).into()); + if target.contains("linux") && arch.starts_with("64") { + cmd.args.push("-mabi=lp64d".into()); + } else if target.contains("linux") && arch.starts_with("32") { + cmd.args.push("-mabi=ilp32d".into()); + } else if arch.starts_with("64") { + cmd.args.push("-mabi=lp64".into()); + } else { + cmd.args.push("-mabi=ilp32".into()); + } + cmd.args.push("-mcmodel=medany".into()); + } + } + } + } + + if target.contains("-ios") { + // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be + // detected instead. + self.ios_flags(cmd)?; + } + + if self.static_flag.unwrap_or(false) { + cmd.args.push("-static".into()); + } + if self.shared_flag.unwrap_or(false) { + cmd.args.push("-shared".into()); + } + + if self.cpp { + match (self.cpp_set_stdlib.as_ref(), cmd.family) { + (None, _) => {} + (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => { + cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); + } + _ => { + println!( + "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ + does not support this option, ignored", + cmd.family + ); + } + } + } + + Ok(()) + } + + fn has_flags(&self) -> bool { + let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; + let flags_env_var_value = self.get_var(flags_env_var_name); + if let Ok(_) = flags_env_var_value { + true + } else { + false + } + } + + fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { + let target = self.get_target()?; + let tool = if target.contains("x86_64") { + "ml64.exe" + } else if target.contains("arm") { + "armasm.exe" + } else if target.contains("aarch64") { + "armasm64.exe" + } else { + "ml.exe" + }; + let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + cmd.arg("-nologo"); // undocumented, yet working with armasm[64] + for directory in self.include_directories.iter() { + cmd.arg("-I").arg(directory); + } + if target.contains("aarch64") || target.contains("arm") { + println!("cargo:warning=The MSVC ARM assemblers do not support -D flags"); + } else { + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.arg(&format!("-D{}={}", key, value)); + } else { + cmd.arg(&format!("-D{}", key)); + } + } + } + + if target.contains("i686") || target.contains("i586") { + cmd.arg("-safeseh"); + } + for flag in self.flags.iter() { + cmd.arg(flag); + } + + Ok((cmd, tool.to_string())) + } + + fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> { + // Delete the destination if it exists as we want to + // create on the first iteration instead of appending. + let _ = fs::remove_file(&dst); + + // Add objects to the archive in limited-length batches. This helps keep + // the length of the command line within a reasonable length to avoid + // blowing system limits on limiting platforms like Windows. + let objs: Vec<_> = objs + .iter() + .map(|o| o.dst.clone()) + .chain(self.objects.clone()) + .collect(); + for chunk in objs.chunks(100) { + self.assemble_progressive(dst, chunk)?; + } + + let target = self.get_target()?; + if target.contains("msvc") { + // The Rust compiler will look for libfoo.a and foo.lib, but the + // MSVC linker will also be passed foo.lib, so be sure that both + // exist for now. + + let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); + let _ = fs::remove_file(&lib_dst); + match fs::hard_link(&dst, &lib_dst).or_else(|_| { + // if hard-link fails, just copy (ignoring the number of bytes written) + fs::copy(&dst, &lib_dst).map(|_| ()) + }) { + Ok(_) => (), + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Could not copy or create a hard-link to the generated lib file.", + )); + } + }; + } else { + // Non-msvc targets (those using `ar`) need a separate step to add + // the symbol table to archives since our construction command of + // `cq` doesn't add it for us. + let (mut ar, cmd) = self.get_ar()?; + run(ar.arg("s").arg(dst), &cmd)?; + } + + Ok(()) + } + + fn assemble_progressive(&self, dst: &Path, objs: &[PathBuf]) -> Result<(), Error> { + let target = self.get_target()?; + + if target.contains("msvc") { + let (mut cmd, program) = self.get_ar()?; + let mut out = OsString::from("-out:"); + out.push(dst); + cmd.arg(out).arg("-nologo"); + for flag in self.ar_flags.iter() { + cmd.arg(flag); + } + // If the library file already exists, add the libary name + // as an argument to let lib.exe know we are appending the objs. + if dst.exists() { + cmd.arg(dst); + } + cmd.args(objs); + run(&mut cmd, &program)?; + } else { + let (mut ar, cmd) = self.get_ar()?; + + // Set an environment variable to tell the OSX archiver to ensure + // that all dates listed in the archive are zero, improving + // determinism of builds. AFAIK there's not really official + // documentation of this but there's a lot of references to it if + // you search google. + // + // You can reproduce this locally on a mac with: + // + // $ touch foo.c + // $ cc -c foo.c -o foo.o + // + // # Notice that these two checksums are different + // $ ar crus libfoo1.a foo.o && sleep 2 && ar crus libfoo2.a foo.o + // $ md5sum libfoo*.a + // + // # Notice that these two checksums are the same + // $ export ZERO_AR_DATE=1 + // $ ar crus libfoo1.a foo.o && sleep 2 && touch foo.o && ar crus libfoo2.a foo.o + // $ md5sum libfoo*.a + // + // In any case if this doesn't end up getting read, it shouldn't + // cause that many issues! + ar.env("ZERO_AR_DATE", "1"); + for flag in self.ar_flags.iter() { + ar.arg(flag); + } + run(ar.arg("cq").arg(dst).args(objs), &cmd)?; + } + + Ok(()) + } + + fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> { + enum ArchSpec { + Device(&'static str), + Simulator(&'static str), + Catalyst(&'static str), + } + + let target = self.get_target()?; + let arch = target.split('-').nth(0).ok_or_else(|| { + Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + ) + })?; + + let is_catalyst = match target.split('-').nth(3) { + Some(v) => v == "macabi", + None => false, + }; + + let arch = if is_catalyst { + match arch { + "arm64e" => ArchSpec::Catalyst("arm64e"), + "arm64" | "aarch64" => ArchSpec::Catalyst("arm64"), + "x86_64" => ArchSpec::Catalyst("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } + } + } else { + match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64e" => ArchSpec::Device("arm64e"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } + } + }; + + let min_version = + std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into()); + + let sdk = match arch { + ArchSpec::Device(arch) => { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + cmd.args + .push(format!("-miphoneos-version-min={}", min_version).into()); + "iphoneos" + } + ArchSpec::Simulator(arch) => { + cmd.args.push(arch.into()); + cmd.args + .push(format!("-mios-simulator-version-min={}", min_version).into()); + "iphonesimulator" + } + ArchSpec::Catalyst(_) => "macosx", + }; + + self.print(&format!("Detecting iOS SDK path for {}", sdk)); + let sdk_path = self.apple_sdk_root(sdk)?; + cmd.args.push("-isysroot".into()); + cmd.args.push(sdk_path); + cmd.args.push("-fembed-bitcode".into()); + /* + * TODO we probably ultimately want the -fembed-bitcode-marker flag + * but can't have it now because of an issue in LLVM: + * https://github.com/alexcrichton/cc-rs/issues/301 + * https://github.com/rust-lang/rust/pull/48896#comment-372192660 + */ + /* + if self.get_opt_level()? == "0" { + cmd.args.push("-fembed-bitcode-marker".into()); + } + */ + + Ok(()) + } + + fn cmd>(&self, prog: P) -> Command { + let mut cmd = Command::new(prog); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd + } + + fn get_base_compiler(&self) -> Result { + if let Some(ref c) = self.compiler { + return Ok(Tool::new(c.clone())); + } + let host = self.get_host()?; + let target = self.get_target()?; + let (env, msvc, gnu, traditional, clang) = if self.cpp { + ("CXX", "cl.exe", "g++", "c++", "clang++") + } else { + ("CC", "cl.exe", "gcc", "cc", "clang") + }; + + // On historical Solaris systems, "cc" may have been Sun Studio, which + // is not flag-compatible with "gcc". This history casts a long shadow, + // and many modern illumos distributions today ship GCC as "gcc" without + // also making it available as "cc". + let default = if host.contains("solaris") || host.contains("illumos") { + gnu + } else { + traditional + }; + + let cl_exe = windows_registry::find_tool(&target, "cl.exe"); + + let tool_opt: Option = self + .env_tool(env) + .map(|(tool, wrapper, args)| { + // find the driver mode, if any + const DRIVER_MODE: &str = "--driver-mode="; + let driver_mode = args + .iter() + .find(|a| a.starts_with(DRIVER_MODE)) + .map(|a| &a[DRIVER_MODE.len()..]); + // Chop off leading/trailing whitespace to work around + // semi-buggy build scripts which are shared in + // makefiles/configure scripts (where spaces are far more + // lenient) + let mut t = Tool::with_clang_driver(PathBuf::from(tool.trim()), driver_mode); + if let Some(cc_wrapper) = wrapper { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + for arg in args { + t.cc_wrapper_args.push(arg.into()); + } + t + }) + .or_else(|| { + if target.contains("emscripten") { + let tool = if self.cpp { "em++" } else { "emcc" }; + // Windows uses bat file so we have to be a bit more specific + if cfg!(windows) { + let mut t = Tool::new(PathBuf::from("cmd")); + t.args.push("/c".into()); + t.args.push(format!("{}.bat", tool).into()); + Some(t) + } else { + Some(Tool::new(PathBuf::from(tool))) + } + } else { + None + } + }) + .or_else(|| cl_exe.clone()); + + let tool = match tool_opt { + Some(t) => t, + None => { + let compiler = if host.contains("windows") && target.contains("windows") { + if target.contains("msvc") { + msvc.to_string() + } else { + format!("{}.exe", gnu) + } + } else if target.contains("android") { + autodetect_android_compiler(&target, &host, gnu, clang) + } else if target.contains("cloudabi") { + format!("{}-{}", target, traditional) + } else if target == "wasm32-wasi" + || target == "wasm32-unknown-wasi" + || target == "wasm32-unknown-unknown" + { + "clang".to_string() + } else if target.contains("vxworks") { + if self.cpp { + "wr-c++".to_string() + } else { + "wr-cc".to_string() + } + } else if self.get_host()? != target { + let prefix = self.prefix_for_target(&target); + match prefix { + Some(prefix) => format!("{}-{}", prefix, gnu), + None => default.to_string(), + } + } else { + default.to_string() + }; + + let mut t = Tool::new(PathBuf::from(compiler)); + if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + t + } + }; + + let mut tool = if self.cuda { + assert!( + tool.args.is_empty(), + "CUDA compilation currently assumes empty pre-existing args" + ); + let nvcc = match self.get_var("NVCC") { + Err(_) => "nvcc".into(), + Ok(nvcc) => nvcc, + }; + let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), None, self.cuda); + nvcc_tool + .args + .push(format!("-ccbin={}", tool.path.display()).into()); + nvcc_tool.family = tool.family; + nvcc_tool + } else { + tool + }; + + // New "standalone" C/C++ cross-compiler executables from recent Android NDK + // are just shell scripts that call main clang binary (from Android NDK) with + // proper `--target` argument. + // + // For example, armv7a-linux-androideabi16-clang passes + // `--target=armv7a-linux-androideabi16` to clang. + // + // As the shell script calls the main clang binary, the command line limit length + // on Windows is restricted to around 8k characters instead of around 32k characters. + // To remove this limit, we call the main clang binary directly and contruct the + // `--target=` ourselves. + if host.contains("windows") && android_clang_compiler_uses_target_arg_internally(&tool.path) + { + if let Some(path) = tool.path.file_name() { + let file_name = path.to_str().unwrap().to_owned(); + let (target, clang) = file_name.split_at(file_name.rfind("-").unwrap()); + + tool.path.set_file_name(clang.trim_start_matches("-")); + tool.path.set_extension("exe"); + tool.args.push(format!("--target={}", target).into()); + + // Additionally, shell scripts for target i686-linux-android versions 16 to 24 + // pass the `mstackrealign` option so we do that here as well. + if target.contains("i686-linux-android") { + let (_, version) = target.split_at(target.rfind("d").unwrap() + 1); + if let Ok(version) = version.parse::() { + if version > 15 && version < 25 { + tool.args.push("-mstackrealign".into()); + } + } + } + }; + } + + // If we found `cl.exe` in our environment, the tool we're returning is + // an MSVC-like tool, *and* no env vars were set then set env vars for + // the tool that we're returning. + // + // Env vars are needed for things like `link.exe` being put into PATH as + // well as header include paths sometimes. These paths are automatically + // included by default but if the `CC` or `CXX` env vars are set these + // won't be used. This'll ensure that when the env vars are used to + // configure for invocations like `clang-cl` we still get a "works out + // of the box" experience. + if let Some(cl_exe) = cl_exe { + if tool.family == (ToolFamily::Msvc { clang_cl: true }) + && tool.env.len() == 0 + && target.contains("msvc") + { + for &(ref k, ref v) in cl_exe.env.iter() { + tool.env.push((k.to_owned(), v.to_owned())); + } + } + } + + Ok(tool) + } + + fn get_var(&self, var_base: &str) -> Result { + let target = self.get_target()?; + let host = self.get_host()?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + let res = self + .getenv(&format!("{}_{}", var_base, target)) + .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) + .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) + .or_else(|| self.getenv(var_base)); + + match res { + Some(res) => Ok(res), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Could not find environment variable {}.", var_base), + )), + } + } + + fn envflags(&self, name: &str) -> Vec { + self.get_var(name) + .unwrap_or(String::new()) + .split_ascii_whitespace() + .map(|slice| slice.to_string()) + .collect() + } + + /// Returns a fallback `cc_compiler_wrapper` by introspecting `RUSTC_WRAPPER` + fn rustc_wrapper_fallback() -> Option { + // No explicit CC wrapper was detected, but check if RUSTC_WRAPPER + // is defined and is a build accelerator that is compatible with + // C/C++ compilers (e.g. sccache) + let valid_wrappers = ["sccache"]; + + let rustc_wrapper = std::env::var_os("RUSTC_WRAPPER")?; + let wrapper_path = Path::new(&rustc_wrapper); + let wrapper_stem = wrapper_path.file_stem()?; + + if valid_wrappers.contains(&wrapper_stem.to_str()?) { + Some(rustc_wrapper.to_str()?.to_owned()) + } else { + None + } + } + + /// Returns compiler path, optional modifier name from whitelist, and arguments vec + fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { + let tool = match self.get_var(name) { + Ok(tool) => tool, + Err(_) => return None, + }; + + // If this is an exact path on the filesystem we don't want to do any + // interpretation at all, just pass it on through. This'll hopefully get + // us to support spaces-in-paths. + if Path::new(&tool).exists() { + return Some((tool, None, Vec::new())); + } + + // Ok now we want to handle a couple of scenarios. We'll assume from + // here on out that spaces are splitting separate arguments. Two major + // features we want to support are: + // + // CC='sccache cc' + // + // aka using `sccache` or any other wrapper/caching-like-thing for + // compilations. We want to know what the actual compiler is still, + // though, because our `Tool` API support introspection of it to see + // what compiler is in use. + // + // additionally we want to support + // + // CC='cc -flag' + // + // where the CC env var is used to also pass default flags to the C + // compiler. + // + // It's true that everything here is a bit of a pain, but apparently if + // you're not literally make or bash then you get a lot of bug reports. + let known_wrappers = ["ccache", "distcc", "sccache", "icecc"]; + + let mut parts = tool.split_whitespace(); + let maybe_wrapper = match parts.next() { + Some(s) => s, + None => return None, + }; + + let file_stem = Path::new(maybe_wrapper) + .file_stem() + .unwrap() + .to_str() + .unwrap(); + if known_wrappers.contains(&file_stem) { + if let Some(compiler) = parts.next() { + return Some(( + compiler.to_string(), + Some(maybe_wrapper.to_string()), + parts.map(|s| s.to_string()).collect(), + )); + } + } + + Some(( + maybe_wrapper.to_string(), + Self::rustc_wrapper_fallback(), + parts.map(|s| s.to_string()).collect(), + )) + } + + /// Returns the C++ standard library: + /// 1. If [cpp_link_stdlib](cc::Build::cpp_link_stdlib) is set, uses its value. + /// 2. Else if the `CXXSTDLIB` environment variable is set, uses its value. + /// 3. Else the default is `libc++` for OS X and BSDs, `libc++_shared` for Android, + /// `None` for MSVC and `libstdc++` for anything else. + fn get_cpp_link_stdlib(&self) -> Result, Error> { + match self.cpp_link_stdlib.clone() { + Some(s) => Ok(s), + None => { + if let Ok(stdlib) = self.get_var("CXXSTDLIB") { + if stdlib.is_empty() { + Ok(None) + } else { + Ok(Some(stdlib)) + } + } else { + let target = self.get_target()?; + if target.contains("msvc") { + Ok(None) + } else if target.contains("apple") { + Ok(Some("c++".to_string())) + } else if target.contains("freebsd") { + Ok(Some("c++".to_string())) + } else if target.contains("openbsd") { + Ok(Some("c++".to_string())) + } else if target.contains("android") { + Ok(Some("c++_shared".to_string())) + } else { + Ok(Some("stdc++".to_string())) + } + } + } + } + } + + fn get_ar(&self) -> Result<(Command, String), Error> { + if let Some(ref p) = self.archiver { + let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); + return Ok((self.cmd(p), name.to_string())); + } + if let Ok(p) = self.get_var("AR") { + return Ok((self.cmd(&p), p)); + } + let target = self.get_target()?; + let default_ar = "ar".to_string(); + let program = if target.contains("android") { + format!("{}-ar", target.replace("armv7", "arm")) + } else if target.contains("emscripten") { + // Windows use bat files so we have to be a bit more specific + if cfg!(windows) { + let mut cmd = self.cmd("cmd"); + cmd.arg("/c").arg("emar.bat"); + return Ok((cmd, "emar.bat".to_string())); + } + + "emar".to_string() + } else if target.contains("msvc") { + match windows_registry::find(&target, "lib.exe") { + Some(t) => return Ok((t, "lib.exe".to_string())), + None => "lib.exe".to_string(), + } + } else if self.get_host()? != target { + match self.prefix_for_target(&target) { + Some(p) => { + let target_ar = format!("{}-ar", p); + if Command::new(&target_ar).output().is_ok() { + target_ar + } else { + default_ar + } + } + None => default_ar, + } + } else { + default_ar + }; + Ok((self.cmd(&program), program)) + } + + fn prefix_for_target(&self, target: &str) -> Option { + // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" + let cc_env = self.getenv("CROSS_COMPILE"); + let cross_compile = cc_env + .as_ref() + .map(|s| s.trim_right_matches('-').to_owned()); + cross_compile.or(match &target[..] { + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), + "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"), + "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), + "hexagon-unknown-linux-musl" => Some("hexagon-linux-musl"), + "i586-unknown-linux-musl" => Some("musl"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-uwp-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsd" => Some("i486--netbsdelf"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mips-unknown-linux-musl" => Some("mips-linux-musl"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mipsel-unknown-linux-musl" => Some("mipsel-linux-musl"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), + "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), + "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), + "mipsisa64r6el-unknown-linux-gnuabi64" => Some("mipsisa64r6el-linux-gnuabi64"), + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "riscv32i-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-linux-gnu" => Some("riscv64-linux-gnu"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), + "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), + "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), + "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), + "armv7a-none-eabi" => Some("arm-none-eabi"), + "armv7a-none-eabihf" => Some("arm-none-eabi"), + "armebv7r-none-eabi" => Some("arm-none-eabi"), + "armebv7r-none-eabihf" => Some("arm-none-eabi"), + "armv7r-none-eabi" => Some("arm-none-eabi"), + "armv7r-none-eabihf" => Some("arm-none-eabi"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-uwp-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + } + .map(|x| x.to_owned())) + } + + /// Some platforms have multiple, compatible, canonical prefixes. Look through + /// each possible prefix for a compiler that exists and return it. The prefixes + /// should be ordered from most-likely to least-likely. + fn find_working_gnu_prefix(&self, prefixes: &[&'static str]) -> Option<&'static str> { + let suffix = if self.cpp { "-g++" } else { "-gcc" }; + let extension = std::env::consts::EXE_SUFFIX; + + // Loop through PATH entries searching for each toolchain. This ensures that we + // are more likely to discover the toolchain early on, because chances are good + // that the desired toolchain is in one of the higher-priority paths. + env::var_os("PATH") + .as_ref() + .and_then(|path_entries| { + env::split_paths(path_entries).find_map(|path_entry| { + for prefix in prefixes { + let target_compiler = format!("{}{}{}", prefix, suffix, extension); + if path_entry.join(&target_compiler).exists() { + return Some(prefix); + } + } + None + }) + }) + .map(|prefix| *prefix) + .or_else(|| + // If no toolchain was found, provide the first toolchain that was passed in. + // This toolchain has been shown not to exist, however it will appear in the + // error that is shown to the user which should make it easier to search for + // where it should be obtained. + prefixes.first().map(|prefix| *prefix)) + } + + fn get_target(&self) -> Result { + match self.target.clone() { + Some(t) => Ok(t), + None => Ok(self.getenv_unwrap("TARGET")?), + } + } + + fn get_host(&self) -> Result { + match self.host.clone() { + Some(h) => Ok(h), + None => Ok(self.getenv_unwrap("HOST")?), + } + } + + fn get_opt_level(&self) -> Result { + match self.opt_level.as_ref().cloned() { + Some(ol) => Ok(ol), + None => Ok(self.getenv_unwrap("OPT_LEVEL")?), + } + } + + fn get_debug(&self) -> bool { + self.debug.unwrap_or_else(|| match self.getenv("DEBUG") { + Some(s) => s != "false", + None => false, + }) + } + + fn get_force_frame_pointer(&self) -> bool { + self.force_frame_pointer.unwrap_or_else(|| self.get_debug()) + } + + fn get_out_dir(&self) -> Result { + match self.out_dir.clone() { + Some(p) => Ok(p), + None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| { + Error::new( + ErrorKind::EnvVarNotFound, + "Environment variable OUT_DIR not defined.", + ) + })?), + } + } + + fn getenv(&self, v: &str) -> Option { + let mut cache = self.env_cache.lock().unwrap(); + if let Some(val) = cache.get(v) { + return val.clone(); + } + let r = env::var(v).ok(); + self.print(&format!("{} = {:?}", v, r)); + cache.insert(v.to_string(), r.clone()); + r + } + + fn getenv_unwrap(&self, v: &str) -> Result { + match self.getenv(v) { + Some(s) => Ok(s), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Environment variable {} not defined.", v.to_string()), + )), + } + } + + fn print(&self, s: &str) { + if self.cargo_metadata { + println!("{}", s); + } + } + + fn fix_env_for_apple_os(&self, cmd: &mut Command) -> Result<(), Error> { + let target = self.get_target()?; + let host = self.get_host()?; + if host.contains("apple-darwin") && target.contains("apple-darwin") { + // If, for example, `cargo` runs during the build of an XCode project, then `SDKROOT` environment variable + // would represent the current target, and this is the problem for us, if we want to compile something + // for the host, when host != target. + // We can not just remove `SDKROOT`, because, again, for example, XCode add to PATH + // /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin + // and `cc` from this path can not find system include files, like `pthread.h`, if `SDKROOT` + // is not set + if let Ok(sdkroot) = env::var("SDKROOT") { + if !sdkroot.contains("MacOSX") { + let macos_sdk = self.apple_sdk_root("macosx")?; + cmd.env("SDKROOT", macos_sdk); + } + } + // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at + // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", + // although this is apparently ignored when using the linker at "/usr/bin/ld". + cmd.env_remove("IPHONEOS_DEPLOYMENT_TARGET"); + } + Ok(()) + } + + fn apple_sdk_root(&self, sdk: &str) -> Result { + let mut cache = self + .apple_sdk_root_cache + .lock() + .expect("apple_sdk_root_cache lock failed"); + if let Some(ret) = cache.get(sdk) { + return Ok(ret.clone()); + } + + let sdk_path = run_output( + self.cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk), + "xcrun", + )?; + + let sdk_path = match String::from_utf8(sdk_path) { + Ok(p) => p, + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Unable to determine iOS SDK path.", + )); + } + }; + let ret: OsString = sdk_path.trim().into(); + cache.insert(sdk.into(), ret.clone()); + Ok(ret) + } +} + +impl Default for Build { + fn default() -> Build { + Build::new() + } +} + +impl Tool { + fn new(path: PathBuf) -> Self { + Tool::with_features(path, None, false) + } + + fn with_clang_driver(path: PathBuf, clang_driver: Option<&str>) -> Self { + Self::with_features(path, clang_driver, false) + } + + #[cfg(windows)] + /// Explictly set the `ToolFamily`, skipping name-based detection. + fn with_family(path: PathBuf, family: ToolFamily) -> Self { + Self { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: false, + removed_args: Vec::new(), + } + } + + fn with_features(path: PathBuf, clang_driver: Option<&str>, cuda: bool) -> Self { + // Try to detect family of the tool from its name, falling back to Gnu. + let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { + if fname.contains("clang-cl") { + ToolFamily::Msvc { clang_cl: true } + } else if fname.contains("cl") + && !fname.contains("cloudabi") + && !fname.contains("uclibc") + && !fname.contains("clang") + { + ToolFamily::Msvc { clang_cl: false } + } else if fname.contains("clang") { + match clang_driver { + Some("cl") => ToolFamily::Msvc { clang_cl: true }, + _ => ToolFamily::Clang, + } + } else { + ToolFamily::Gnu + } + } else { + ToolFamily::Gnu + }; + + Tool { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: cuda, + removed_args: Vec::new(), + } + } + + /// Add an argument to be stripped from the final command arguments. + fn remove_arg(&mut self, flag: OsString) { + self.removed_args.push(flag); + } + + /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler". + /// + /// Currently this is only used for compiling CUDA sources, since NVCC only + /// accepts a limited set of GNU-like flags, and the rest must be prefixed + /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. + fn push_cc_arg(&mut self, flag: OsString) { + if self.cuda { + self.args.push("-Xcompiler".into()); + } + self.args.push(flag); + } + + fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool { + let flag = flag.to_str().unwrap(); + let mut chars = flag.chars(); + + // Only duplicate check compiler flags + if self.is_like_msvc() { + if chars.next() != Some('/') { + return false; + } + } else if self.is_like_gnu() || self.is_like_clang() { + if chars.next() != Some('-') { + return false; + } + } + + // Check for existing optimization flags (-O, /O) + if chars.next() == Some('O') { + return self + .args() + .iter() + .any(|ref a| a.to_str().unwrap_or("").chars().nth(1) == Some('O')); + } + + // TODO Check for existing -m..., -m...=..., /arch:... flags + return false; + } + + /// Don't push optimization arg if it conflicts with existing args + fn push_opt_unless_duplicate(&mut self, flag: OsString) { + if self.is_duplicate_opt_arg(&flag) { + println!("Info: Ignoring duplicate arg {:?}", &flag); + } else { + self.push_cc_arg(flag); + } + } + + /// Converts this compiler into a `Command` that's ready to be run. + /// + /// This is useful for when the compiler needs to be executed and the + /// command returned will already have the initial arguments and environment + /// variables configured. + pub fn to_command(&self) -> Command { + let mut cmd = match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cmd = Command::new(&cc_wrapper_path); + cmd.arg(&self.path); + cmd + } + None => Command::new(&self.path), + }; + cmd.args(&self.cc_wrapper_args); + + let value = self + .args + .iter() + .filter(|a| !self.removed_args.contains(a)) + .collect::>(); + cmd.args(&value); + + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + cmd + } + + /// Returns the path for this compiler. + /// + /// Note that this may not be a path to a file on the filesystem, e.g. "cc", + /// but rather something which will be resolved when a process is spawned. + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the default set of arguments to the compiler needed to produce + /// executables for the target this compiler generates. + pub fn args(&self) -> &[OsString] { + &self.args + } + + /// Returns the set of environment variables needed for this compiler to + /// operate. + /// + /// This is typically only used for MSVC compilers currently. + pub fn env(&self) -> &[(OsString, OsString)] { + &self.env + } + + /// Returns the compiler command in format of CC environment variable. + /// Or empty string if CC env was not present + /// + /// This is typically used by configure script + pub fn cc_env(&self) -> OsString { + match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cc_env = cc_wrapper_path.as_os_str().to_owned(); + cc_env.push(" "); + cc_env.push(self.path.to_path_buf().into_os_string()); + for arg in self.cc_wrapper_args.iter() { + cc_env.push(" "); + cc_env.push(arg); + } + cc_env + } + None => OsString::from(""), + } + } + + /// Returns the compiler flags in format of CFLAGS environment variable. + /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS + /// This is typically used by configure script + pub fn cflags_env(&self) -> OsString { + let mut flags = OsString::new(); + for (i, arg) in self.args.iter().enumerate() { + if i > 0 { + flags.push(" "); + } + flags.push(arg); + } + flags + } + + /// Whether the tool is GNU Compiler Collection-like. + pub fn is_like_gnu(&self) -> bool { + self.family == ToolFamily::Gnu + } + + /// Whether the tool is Clang-like. + pub fn is_like_clang(&self) -> bool { + self.family == ToolFamily::Clang + } + + /// Whether the tool is MSVC-like. + pub fn is_like_msvc(&self) -> bool { + match self.family { + ToolFamily::Msvc { .. } => true, + _ => false, + } + } +} + +fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { + let (mut child, print) = spawn(cmd, program)?; + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { + cmd.stdout(Stdio::piped()); + let (mut child, print) = spawn(cmd, program)?; + let mut stdout = vec![]; + child + .stdout + .take() + .unwrap() + .read_to_end(&mut stdout) + .unwrap(); + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(stdout) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Error> { + println!("running: {:?}", cmd); + + // Capture the standard error coming from these programs, and write it out + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // requiring the output to be UTF-8, we instead just ship bytes from one + // location to another. + match cmd.stderr(Stdio::piped()).spawn() { + Ok(mut child) => { + let stderr = BufReader::new(child.stderr.take().unwrap()); + let print = thread::spawn(move || { + for line in stderr.split(b'\n').filter_map(|l| l.ok()) { + print!("cargo:warning="); + std::io::stdout().write_all(&line).unwrap(); + println!(""); + } + }); + Ok((child, print)) + } + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let extra = if cfg!(windows) { + " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \ + for help)" + } else { + "" + }; + Err(Error::new( + ErrorKind::ToolNotFound, + &format!("Failed to find tool. Is `{}` installed?{}", program, extra), + )) + } + Err(_) => Err(Error::new( + ErrorKind::ToolExecError, + &format!("Command {:?} with args {:?} failed to start.", cmd, program), + )), + } +} + +fn fail(s: &str) -> ! { + let _ = writeln!(io::stderr(), "\n\nerror occurred: {}\n\n", s); + std::process::exit(1); +} + +fn command_add_output_file( + cmd: &mut Command, + dst: &Path, + cuda: bool, + msvc: bool, + clang: bool, + is_asm: bool, + is_arm: bool, +) { + if msvc && !clang && !cuda && !(is_asm && is_arm) { + let mut s = OsString::from("-Fo"); + s.push(&dst); + cmd.arg(s); + } else { + cmd.arg("-o").arg(&dst); + } +} + +// Use by default minimum available API level +// See note about naming here +// https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md#Clang +static NEW_STANDALONE_ANDROID_COMPILERS: [&str; 4] = [ + "aarch64-linux-android21-clang", + "armv7a-linux-androideabi16-clang", + "i686-linux-android16-clang", + "x86_64-linux-android21-clang", +]; + +// New "standalone" C/C++ cross-compiler executables from recent Android NDK +// are just shell scripts that call main clang binary (from Android NDK) with +// proper `--target` argument. +// +// For example, armv7a-linux-androideabi16-clang passes +// `--target=armv7a-linux-androideabi16` to clang. +// So to construct proper command line check if +// `--target` argument would be passed or not to clang +fn android_clang_compiler_uses_target_arg_internally(clang_path: &Path) -> bool { + if let Some(filename) = clang_path.file_name() { + if let Some(filename_str) = filename.to_str() { + filename_str.contains("android") + } else { + false + } + } else { + false + } +} + +#[test] +fn test_android_clang_compiler_uses_target_arg_internally() { + for version in 16..21 { + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang", version)) + )); + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang++", version)) + )); + } + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang") + )); + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang++") + )); +} + +fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) -> String { + let new_clang_key = match target { + "aarch64-linux-android" => Some("aarch64"), + "armv7-linux-androideabi" => Some("armv7a"), + "i686-linux-android" => Some("i686"), + "x86_64-linux-android" => Some("x86_64"), + _ => None, + }; + + let new_clang = new_clang_key + .map(|key| { + NEW_STANDALONE_ANDROID_COMPILERS + .iter() + .find(|x| x.starts_with(key)) + }) + .unwrap_or(None); + + if let Some(new_clang) = new_clang { + if Command::new(new_clang).output().is_ok() { + return (*new_clang).into(); + } + } + + let target = target + .replace("armv7neon", "arm") + .replace("armv7", "arm") + .replace("thumbv7neon", "arm") + .replace("thumbv7", "arm"); + let gnu_compiler = format!("{}-{}", target, gnu); + let clang_compiler = format!("{}-{}", target, clang); + + // On Windows, the Android clang compiler is provided as a `.cmd` file instead + // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the + // `.cmd` is explicitly appended to the command name, so we do that here. + let clang_compiler_cmd = format!("{}-{}.cmd", target, clang); + + // Check if gnu compiler is present + // if not, use clang + if Command::new(&gnu_compiler).output().is_ok() { + gnu_compiler + } else if host.contains("windows") && Command::new(&clang_compiler_cmd).output().is_ok() { + clang_compiler_cmd + } else { + clang_compiler + } +} + +// Rust and clang/cc don't agree on how to name the target. +fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option<&'static str> { + if target.contains("x86_64") { + Some("x86_64") + } else if target.contains("arm64e") { + Some("arm64e") + } else if target.contains("aarch64") { + Some("arm64") + } else { + None + } +} diff --git a/third_party/cargo/vendor/cc-1.0.54/src/registry.rs b/third_party/cargo/vendor/cc-1.0.66/src/registry.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/src/registry.rs rename to third_party/cargo/vendor/cc-1.0.66/src/registry.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/src/setup_config.rs b/third_party/cargo/vendor/cc-1.0.66/src/setup_config.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/src/setup_config.rs rename to third_party/cargo/vendor/cc-1.0.66/src/setup_config.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/src/winapi.rs b/third_party/cargo/vendor/cc-1.0.66/src/winapi.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/src/winapi.rs rename to third_party/cargo/vendor/cc-1.0.66/src/winapi.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/src/windows_registry.rs b/third_party/cargo/vendor/cc-1.0.66/src/windows_registry.rs similarity index 97% rename from third_party/cargo/vendor/cc-1.0.54/src/windows_registry.rs rename to third_party/cargo/vendor/cc-1.0.66/src/windows_registry.rs index a5e07d4..8172502 100644 --- a/third_party/cargo/vendor/cc-1.0.54/src/windows_registry.rs +++ b/third_party/cargo/vendor/cc-1.0.66/src/windows_registry.rs @@ -347,6 +347,7 @@ mod impl_ { }; let mut tool = MsvcTool::new(tool_path); + tool.path.push(bin_path.clone()); tool.path.push(host_dylib_path); tool.libs.push(lib_path); tool.include.push(include_path); @@ -375,6 +376,9 @@ mod impl_ { let host = match host_arch() { X86 => "X86", X86_64 => "X64", + // There is no natively hosted compiler on ARM64. + // Instead, use the x86 toolchain under emulation (there is no x64 emulation). + AARCH64 => "X86", _ => return None, }; let target = lib_subdir(target)?; @@ -421,8 +425,15 @@ mod impl_ { let sub = lib_subdir(target)?; let (ucrt, ucrt_version) = get_ucrt_dir()?; + let host = match host_arch() { + X86 => "x86", + X86_64 => "x64", + AARCH64 => "arm64", + _ => return None, + }; + tool.path - .push(ucrt.join("bin").join(&ucrt_version).join(sub)); + .push(ucrt.join("bin").join(&ucrt_version).join(host)); let ucrt_include = ucrt.join("include").join(&ucrt_version); tool.include.push(ucrt_include.join("ucrt")); @@ -431,7 +442,7 @@ mod impl_ { tool.libs.push(ucrt_lib.join("ucrt").join(sub)); if let Some((sdk, version)) = get_sdk10_dir() { - tool.path.push(sdk.join("bin").join(sub)); + tool.path.push(sdk.join("bin").join(host)); let sdk_lib = sdk.join("lib").join(&version); tool.libs.push(sdk_lib.join("um").join(sub)); let sdk_include = sdk.join("include").join(&version); @@ -440,7 +451,7 @@ mod impl_ { tool.include.push(sdk_include.join("winrt")); tool.include.push(sdk_include.join("shared")); } else if let Some(sdk) = get_sdk81_dir() { - tool.path.push(sdk.join("bin").join(sub)); + tool.path.push(sdk.join("bin").join(host)); let sdk_lib = sdk.join("lib").join("winv6.3"); tool.libs.push(sdk_lib.join("um").join(sub)); let sdk_include = sdk.join("include"); @@ -607,8 +618,10 @@ mod impl_ { const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const PROCESSOR_ARCHITECTURE_ARM64: u16 = 12; const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + const AARCH64: u16 = PROCESSOR_ARCHITECTURE_ARM64; // When choosing the tool to use, we have to choose the one which matches // the target architecture. Otherwise we end up in situations where someone diff --git a/third_party/cargo/vendor/cc-1.0.54/tests/cc_env.rs b/third_party/cargo/vendor/cc-1.0.66/tests/cc_env.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/tests/cc_env.rs rename to third_party/cargo/vendor/cc-1.0.66/tests/cc_env.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/tests/cflags.rs b/third_party/cargo/vendor/cc-1.0.66/tests/cflags.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/tests/cflags.rs rename to third_party/cargo/vendor/cc-1.0.66/tests/cflags.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/tests/cxxflags.rs b/third_party/cargo/vendor/cc-1.0.66/tests/cxxflags.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/tests/cxxflags.rs rename to third_party/cargo/vendor/cc-1.0.66/tests/cxxflags.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/tests/support/mod.rs b/third_party/cargo/vendor/cc-1.0.66/tests/support/mod.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/tests/support/mod.rs rename to third_party/cargo/vendor/cc-1.0.66/tests/support/mod.rs diff --git a/third_party/cargo/vendor/cc-1.0.54/tests/test.rs b/third_party/cargo/vendor/cc-1.0.66/tests/test.rs similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/tests/test.rs rename to third_party/cargo/vendor/cc-1.0.66/tests/test.rs diff --git a/third_party/cargo/vendor/cfg-if-1.0.0/.cargo-checksum.json b/third_party/cargo/vendor/cfg-if-1.0.0/.cargo-checksum.json new file mode 100644 index 0000000..93e07c1 --- /dev/null +++ b/third_party/cargo/vendor/cfg-if-1.0.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5b2a8f6e5256957c029cf3a8912d51438e7faa5891c5c102c312f6d4599c1f00","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"2406e83ee174e30aa67f8ab266836fa78545012b196395aff37c152321e2c713","src/lib.rs":"54b0f108b0dc48a077c52c0bcd22b64ef4de083e5e2b7d405e50ae4d78224f1b","tests/xcrate.rs":"c0734dae6e63beafcd60bf53546115a2320735b51035c9e2387fdf9301580934"},"package":"baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cfg-if-1.0.0/BUILD.bazel b/third_party/cargo/vendor/cfg-if-1.0.0/BUILD.bazel new file mode 100644 index 0000000..d9fc006 --- /dev/null +++ b/third_party/cargo/vendor/cfg-if-1.0.0/BUILD.bazel @@ -0,0 +1,55 @@ +""" +@generated +cargo-raze crate build file. + +DO NOT EDIT! Replaced on runs of cargo-raze +""" + +# buildifier: disable=load +load( + "@io_bazel_rules_rust//rust:rust.bzl", + "rust_binary", + "rust_library", + "rust_test", +) + +# buildifier: disable=load +load("@bazel_skylib//lib:selects.bzl", "selects") + +package(default_visibility = [ + # Public for visibility by "@raze__crate__version//" targets. + # + # Prefer access through "//third_party/cargo", which limits external + # visibility to explicit Cargo.toml dependencies. + "//visibility:public", +]) + +licenses([ + "notice", # MIT from expression "MIT OR Apache-2.0" +]) + +# Generated Targets + +rust_library( + name = "cfg_if", + srcs = glob(["**/*.rs"]), + crate_features = [ + ], + crate_root = "src/lib.rs", + crate_type = "lib", + data = [], + edition = "2018", + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-raze", + "manual", + ], + version = "1.0.0", + # buildifier: leave-alone + deps = [ + ], +) + +# Unsupported target "xcrate" with type "test" omitted diff --git a/third_party/cargo/vendor/cfg-if-1.0.0/Cargo.toml b/third_party/cargo/vendor/cfg-if-1.0.0/Cargo.toml new file mode 100644 index 0000000..13a32ba --- /dev/null +++ b/third_party/cargo/vendor/cfg-if-1.0.0/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "cfg-if" +version = "1.0.0" +authors = ["Alex Crichton "] +description = "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n" +homepage = "https://github.com/alexcrichton/cfg-if" +documentation = "https://docs.rs/cfg-if" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cfg-if" +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[features] +rustc-dep-of-std = ["core", "compiler_builtins"] +[badges.travis-ci] +repository = "alexcrichton/cfg-if" diff --git a/third_party/cargo/vendor/cc-1.0.54/LICENSE-APACHE b/third_party/cargo/vendor/cfg-if-1.0.0/LICENSE-APACHE similarity index 100% rename from third_party/cargo/vendor/cc-1.0.54/LICENSE-APACHE rename to third_party/cargo/vendor/cfg-if-1.0.0/LICENSE-APACHE diff --git a/third_party/cargo/vendor/cmake-0.1.44/LICENSE-MIT b/third_party/cargo/vendor/cfg-if-1.0.0/LICENSE-MIT similarity index 100% rename from third_party/cargo/vendor/cmake-0.1.44/LICENSE-MIT rename to third_party/cargo/vendor/cfg-if-1.0.0/LICENSE-MIT diff --git a/third_party/cargo/vendor/cfg-if-1.0.0/README.md b/third_party/cargo/vendor/cfg-if-1.0.0/README.md new file mode 100644 index 0000000..50b5e3b --- /dev/null +++ b/third_party/cargo/vendor/cfg-if-1.0.0/README.md @@ -0,0 +1,47 @@ +# cfg-if + +[Documentation](https://docs.rs/cfg-if) + +A macro to ergonomically define an item depending on a large number of #[cfg] +parameters. Structured like an if-else chain, the first matching branch is the +item that gets emitted. + +```toml +[dependencies] +cfg-if = "0.1" +``` + +## Example + +```rust +cfg_if::cfg_if! { + if #[cfg(unix)] { + fn foo() { /* unix specific functionality */ } + } else if #[cfg(target_pointer_width = "32")] { + fn foo() { /* non-unix, 32-bit functionality */ } + } else { + fn foo() { /* fallback implementation */ } + } +} + +fn main() { + foo(); +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `cfg-if` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/cargo/vendor/cfg-if-1.0.0/src/lib.rs b/third_party/cargo/vendor/cfg-if-1.0.0/src/lib.rs new file mode 100644 index 0000000..52bbbe0 --- /dev/null +++ b/third_party/cargo/vendor/cfg-if-1.0.0/src/lib.rs @@ -0,0 +1,176 @@ +//! A macro for defining `#[cfg]` if-else statements. +//! +//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C +//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases, +//! emitting the implementation which matches first. +//! +//! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +//! without having to rewrite each clause multiple times. +//! +//! # Example +//! +//! ``` +//! cfg_if::cfg_if! { +//! if #[cfg(unix)] { +//! fn foo() { /* unix specific functionality */ } +//! } else if #[cfg(target_pointer_width = "32")] { +//! fn foo() { /* non-unix, 32-bit functionality */ } +//! } else { +//! fn foo() { /* fallback implementation */ } +//! } +//! } +//! +//! # fn main() {} +//! ``` + +#![no_std] +#![doc(html_root_url = "https://docs.rs/cfg-if")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +/// The main macro provided by this crate. See crate documentation for more +/// information. +#[macro_export] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($meta:meta)] { $($tokens:tt)* } + ) else * else { + $($tokens2:tt)* + }) => { + $crate::cfg_if! { + @__items + () ; + $( ( ($meta) ($($tokens)*) ), )* + ( () ($($tokens2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($i_met:meta)] { $($i_tokens:tt)* } + $( + else if #[cfg($e_met:meta)] { $($e_tokens:tt)* } + )* + ) => { + $crate::cfg_if! { + @__items + () ; + ( ($i_met) ($($i_tokens)*) ), + $( ( ($e_met) ($($e_tokens)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($tokens:tt)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + #[cfg(all($($m,)* not(any($($not),*))))] $crate::cfg_if! { @__identity $($tokens)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + $crate::cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to make __apply work out right for different match types, + // because of how macros matching/expand stuff. + (@__identity $($tokens:tt)*) => { + $($tokens)* + }; +} + +#[cfg(test)] +mod tests { + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } else { + fn works1() -> Option { None } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works2() -> bool { false } + } else if #[cfg(test)] { + fn works2() -> bool { true } + } else { + fn works2() -> bool { false } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works3() -> bool { false } + } else { + fn works3() -> bool { true } + } + } + + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works5() -> bool { false } + } else if #[cfg(test)] { + fn works5() -> bool { true } + } + } + + #[test] + fn it_works() { + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); + } + + #[test] + #[allow(clippy::assertions_on_constants)] + fn test_usage_within_a_function() { + cfg_if! {if #[cfg(debug_assertions)] { + // we want to put more than one thing here to make sure that they + // all get configured properly. + assert!(cfg!(debug_assertions)); + assert_eq!(4, 2+2); + } else { + assert!(works1().is_some()); + assert_eq!(10, 5+5); + }} + } + + trait Trait { + fn blah(&self); + } + + #[allow(dead_code)] + struct Struct; + + impl Trait for Struct { + cfg_if! { + if #[cfg(feature = "blah")] { + fn blah(&self) { + unimplemented!(); + } + } else { + fn blah(&self) { + unimplemented!(); + } + } + } + } +} diff --git a/third_party/cargo/vendor/cfg-if-1.0.0/tests/xcrate.rs b/third_party/cargo/vendor/cfg-if-1.0.0/tests/xcrate.rs new file mode 100644 index 0000000..e7b4a36 --- /dev/null +++ b/third_party/cargo/vendor/cfg-if-1.0.0/tests/xcrate.rs @@ -0,0 +1,14 @@ +cfg_if::cfg_if! { + if #[cfg(foo)] { + fn works() -> bool { false } + } else if #[cfg(test)] { + fn works() -> bool { true } + } else { + fn works() -> bool { false } + } +} + +#[test] +fn smoke() { + assert!(works()); +} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/.cargo-checksum.json b/third_party/cargo/vendor/cgmath-0.17.0/.cargo-checksum.json deleted file mode 100644 index fa449f5..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"2da9965b39d778331e30375417e8a9dc0412eda7467c65bc338f7b08f8104cd8","Cargo.toml":"0c473a17c57fb8609d353f075491e66ea28b835b26a9895916d92c0382b80041","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"0f8d1be0ee2342b30c3ba1bc5530b9823aade548278925d7c0f57c0aade4cfcd","benches/common/macros.rs":"87bf502fc9726c488a065e6c3a190de078559eb9a74bdc8f2937344e76b1e94f","benches/construction.rs":"7ed917339a838a8252176441fc5fb0b737cf0ac10121436fa4d1cb82ca8325d5","benches/mat.rs":"63e1d7f4e363abf92ca4898a6cf1418cd8b484d88c313f33e96116d0b08f240f","benches/quat.rs":"ace3874169b64ddccb49d9231acf701bdadb2bdb59294eb5931f213087795030","benches/vec.rs":"7f780bdc8f36dd4b3a230c3626f2dc4faaf4b2cd543fa210414a8ca7a9414e87","build.rs":"7aed18c06d7b03df8e737ddeb11c0d716a6bce1f0217f29c9011ebe621bfbd4b","src/angle.rs":"270930870ddfe90b789c308bb562446587c64be3ee1416f419d417060c9e7882","src/conv.rs":"42092eb2b9edd523fc7dd37312343e5d58f8234c32f3683094f3ae2908988811","src/euler.rs":"f1ba30d199a9aafd8ee3d282ac4c2ffed61d2af91fa74539b31a2c00bc59fe05","src/lib.rs":"c5c633392010bcefadd9060a3729fca55300a8695bd31f7f8c025790831e8d90","src/macros.rs":"0781fb116a874f5d396143a362d8cc9ee8cd4d5518403cf3f30d029896e9c58d","src/matrix.rs":"d077d394ce03017892aefa1cd4559db4eb3a52a72c5ef6d16042a0bbf3ab7e76","src/num.rs":"54e2273d0b516de48c14328c08325717d9c8942f23665dd4325b43093263606a","src/point.rs":"d874f486365ee98c689516c0f08e58299ba22a229b12125f4bbf8c54632742d9","src/prelude.rs":"e02daa6ea97d656afb9828cff87cb9caf9567819df72ebcafcb6ed064ccbe616","src/projection.rs":"9963ee9e889b6ead50269b5d93358d65fa0f70417a74eaec195fae320eb049e7","src/quaternion.rs":"e96f430135ffb04306b7d18afa67f59d7f1ed44e44b4a9f187515ffb8713ab48","src/rotation.rs":"2fa93d4ea758550ab93cb1c4a56b605d821a7923e5d8c90c0da42326c3d69fce","src/structure.rs":"1c7d8eadc75da0fc8a45ba4b795bf1d2dcdc3e88e02ba6da7e6bdd4fc6dc6c8a","src/transform.rs":"b65bb8944c8b5759762c7196a921ad86dbc331c34cff25ade15739f01376d554","src/vector.rs":"17edb53c2d0f011ea19097505237697f97bff6fa623749b8d3143cc21f1279ed","tests/angle.rs":"d1e4b06bcd5e37fdb4ff201607c719eb3b116ac840766b24804e78bac39a3e5a","tests/matrix.rs":"58ee6ff98217ce2f81c61ee9d4a6f656e32ae4f04fad92d765f7e0db50fec468","tests/point.rs":"c8f33f2f25903e6de984250a3b6c5818f7ed506662140d5d316151c8107e14ae","tests/projection.rs":"f5156fd39109932726e1633ffcb12e4871a2bbb88469a8e45f74edb9f1b11f0c","tests/quaternion.rs":"f40c98d8ae77b02a8341a42d67268e3b88a9c788f5b5dbfc2cb06d12db49876c","tests/rotation.rs":"af5eb7db5519f10d7ab3e4dab65580c951de167e6f49ef4612e55845767c4698","tests/swizzle.rs":"4e6bd2b7beb70f57512f22f5bd3690a027ca196aef4b9f116c4e5d1a079d00c8","tests/transform.rs":"eaf27d9c4c2121bbd4e45a03654b8ba8d218319a98dd82d79617c91fece3e08a","tests/vector.rs":"56b1883a14accb35f82aa67f16cfc3260bd432bfb1786a0fd2e726537113137e","tests/vector4f32.rs":"61b197eba505fb58f4aec59f0690c2b501c55fdec167e32ae0e6793b53fcf41e"},"package":"283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7"} \ No newline at end of file diff --git a/third_party/cargo/vendor/cgmath-0.17.0/BUILD.bazel b/third_party/cargo/vendor/cgmath-0.17.0/BUILD.bazel deleted file mode 100644 index 793608f..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/BUILD.bazel +++ /dev/null @@ -1,113 +0,0 @@ -""" -@generated -cargo-raze crate build file. - -DO NOT EDIT! Replaced on runs of cargo-raze -""" - -# buildifier: disable=load -load( - "@io_bazel_rules_rust//rust:rust.bzl", - "rust_binary", - "rust_library", - "rust_test", -) - -# buildifier: disable=load -load("@bazel_skylib//lib:selects.bzl", "selects") - -package(default_visibility = [ - # Public for visibility by "@raze__crate__version//" targets. - # - # Prefer access through "//third_party/cargo", which limits external - # visibility to explicit Cargo.toml dependencies. - "//visibility:public", -]) - -licenses([ - "notice", # Apache-2.0 from expression "Apache-2.0" -]) - -# Generated Targets -# buildifier: disable=load-on-top -load( - "@io_bazel_rules_rust//cargo:cargo_build_script.bzl", - "cargo_build_script", -) - -cargo_build_script( - name = "cgmath_build_script", - srcs = glob(["**/*.rs"]), - build_script_env = { - }, - crate_features = [ - ], - crate_root = "build.rs", - data = glob(["**"]), - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.17.0", - visibility = ["//visibility:private"], - deps = [ - ], -) - -# Unsupported target "construction" with type "bench" omitted - -# Unsupported target "mat" with type "bench" omitted - -# Unsupported target "quat" with type "bench" omitted - -# Unsupported target "vec" with type "bench" omitted - -rust_library( - name = "cgmath", - srcs = glob(["**/*.rs"]), - crate_features = [ - ], - crate_root = "src/lib.rs", - crate_type = "lib", - data = [], - edition = "2015", - rustc_flags = [ - "--cap-lints=allow", - ], - tags = [ - "cargo-raze", - "manual", - ], - version = "0.17.0", - # buildifier: leave-alone - deps = [ - ":cgmath_build_script", - "//third_party/cargo/vendor/approx-0.3.2:approx", - "//third_party/cargo/vendor/num-traits-0.2.11:num_traits", - "//third_party/cargo/vendor/rand-0.6.5:rand", - ], -) - -# Unsupported target "angle" with type "test" omitted - -# Unsupported target "matrix" with type "test" omitted - -# Unsupported target "point" with type "test" omitted - -# Unsupported target "projection" with type "test" omitted - -# Unsupported target "quaternion" with type "test" omitted - -# Unsupported target "rotation" with type "test" omitted - -# Unsupported target "swizzle" with type "test" omitted - -# Unsupported target "transform" with type "test" omitted - -# Unsupported target "vector" with type "test" omitted - -# Unsupported target "vector4f32" with type "test" omitted diff --git a/third_party/cargo/vendor/cgmath-0.17.0/CHANGELOG.md b/third_party/cargo/vendor/cgmath-0.17.0/CHANGELOG.md deleted file mode 100755 index 9dcd253..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/CHANGELOG.md +++ /dev/null @@ -1,339 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file, following -the format defined at [keepachangelog.com](http://keepachangelog.com/). -This project adheres to [Semantic Versioning](http://semver.org/). - -## [Unreleased] - -### Changed - - Move `lerp()` from `InnerSpace` to `VectorSpace` - -## [v0.16.1] - 2018-03-21 - -### Added - - - Implement `ElementWise` trait for point types - - Add `map` function to points and vectors - -### Changed - - - Remove `BaseNum` trait requirement for `PointN::new` functions - -## [v0.16.0] - 2018-01-03 - -### Added - -- Add `InnerSpace::project_on` -- Add `Array::len` -- Re-export `Bounded` and implement for vectors, points, and angles -- Add vector subtraction to `EuclideanSpace` -- Add swizzle functions behinde that `"swizzle"` feature -- Add `Matrix4::look_at_dir` - -### Changed - -- Return `Option` from cast functions - -## [v0.15.0] - 2017-07-30 - -### Added - -- Implement `mint` conversions behind a feature -- Add `Quaternion::cast` - -### Changed - -- Rename `use_simd` feature to `simd` -- Rename `eders` feature to `serde` - -### Fixed - -- Fix matrix inversions for small determinants - -## [v0.14.1] - 2017-05-02 - -### Fixed - -- Add a workaround for rust-lang/rust#41478, and in the process cleaned up - some type projections for angles - -## [v0.14.0] - 2017-04-26 - -## Changed - -- Constrain `VectorSpace`, `Rotation`, and `Angle` by `iter::Sum` -- Constrain `SquareMatrix` by `iter::Product` - -## [v0.13.1] - 2017-04-22 - -### Changed - -- Update `serde` and `serde_derive` to version `1.0`. - -## [v0.13.0] - 2017-04-14 - -### Added - -- Add optional `use_simd` feature to improve the performance of `Vector4`, - `Matrix4` and `Quaternion`. According to @DaseinPhaos in #394, under - the given benchmark certain operations were able to become up to 60% faster. -- Add component wise casting for the matrix and point types - -### Changed - -- Update `serde` to version `0.9`, and use `serde_derive` instead of `serde_macros`. - -## [v0.12.0] - 2016-09-14 - -### Changed - -- Use [approx](https://github.com/brendanzab/approx/) for approximate equality - comparisons -- Remove `#[repr(packed)]` from all structs where it was specified -- Update serde to 0.8 - -## [v0.11.0] - 2016-08-17 - -### Added - -- `Quaternion::from_arc` - -### Changed - -- Change the angle types to be tuple structs -- Make from-angle constructors take generic `Into>` values -- Fix `Decomposed::concat` implementation - -## [v0.10.0] - 2016-05-11 - -### Added - -- A `MetricSpace` trait for types that have a distance between elements. -- `EuclideanSpace::{midpoint, centroid}` functions with default - implementations. -- `Vector1` and `Point1` structs. -- Serde support behind the `eders` feature flag. -- An `ApproxEq` implementation for `Decomposed`. - -### Changed - -- Depend on the `num-traits` crate rather than `num`, seeing as we only use the - traits in `num`. `num_traits` has also been re-exported so that you can more - easily use these in your project. -- Use an `Euler` type for euler angle conversions. -- Constrain `InnerSpace` by `MetricSpace`. -- Constrain `Rotation` by `One` -- Implement `Transform` and `Transform3` for `Matrix4`. -- Implement `Transform`, `Transform2`, and `Transform3` for `Matrix4`. -- Fix `Euler`-`Quaternion` and `Quaternion`-`Euler` conversions. The axes are - now correct, and the angles are applied in _x_-_y_-_z_ order. The conversion now - matches the conversion from axis angle. -- Fix `Euler`-`{Matrix3, Matrix4}` conversions. - -## Removed - -- `Rotation::transform_as_point` -- `AffineMatrix3` -- `Rotation::invert_self` -- `Matrix::invert_self` - -## [v0.9.1] - 2016-04-20 - -### Changed - -- Fix angle assignment operators so that they actually mutate `self`. - -## [v0.9.0] - 2016-04-19 - -### Changed - -- Assignment operators implementations have been stabilised, to coincide with - their [stabilisation in Rust 1.8](http://blog.rust-lang.org/2016/04/14/Rust-1.8.html). -- Renames `Vector` trait to `VectorSpace`. -- Renames `EuclideanVector` to `InnerSpace`. -- Renames `Point` to `EuclideanSpace`, and `Point::Vector` to `EuclideanSpace::Diff`. -- `Quaternion`s now implement `VectorSpace` and `InnerSpace` for the functions - they share. -- The `Matrix` trait is now constraint by `VectorSpace`, with `Matrix::Element` - removed in favor of `VectorSpace::Scalar`. - -## [v0.8.0] - 2016-04-06 - -### Added - -- Implements `fmt::Debug` for `Basis2`, `Basis3`, and `AffineMatrix3` -- A `prelude` module for easy importing of common traits. -- Constrained conversion functions for assisting in situations where type - inference is difficult. -- An `ElementWise` trait for non-mathematical element-wise operations. -- A default implementation for `EuclideanVector::angle`. - -### Changed - -- Improves the `fmt::Debug` impls for `Vector`, `Matrix`, `Point`, `Decomposed`, - `Quaternion` and `Angle` to make them easier to derive, and have clearer - formatting. -- Marks vectors, points, matrices, and angles as `#[repr(C, packed)]`. -- Renames the `Vector::{length, length2}` functions to `Vector::{magnitude, magnitude2}`. -- Move `Angle::new` to be directly implemented on the `Rad` and `Deg` types. -- Move `Vector::dot` to `EuclideanVector` trait. -- Move `Vector::from_value` to `Array` trait. - -### Removed - -- The non-mathematical operator trait implementations have been removed from - the `Vector` trait, in favor of the `ElementWise` trait. -- `Angle::equiv`. -- Remove `neg_self` method on vectors and matrices. - -## [v0.7.0] - 2015-12-23 - -### Added -- Add missing by-ref and by-val permutations of `Vector`, `Matrix`, `Point`, - `Quaternion` and `Angle` operators. -- Ease lifetime constraints by removing `'static` from some scalar type - parameters. -- Weaken type constraints on `perspective` function to take an `Into>`. -- Add `Angle::new` for constructing angles from a unitless scalar. -- Implement assignment operators for nightly builds, enabled by the `"unstable"` - feature. - -### Changed -- `Vector`, `Matrix`, `Point`, and `Angle` are now constrained to require - specific operators to be overloaded. This means that generic code can now use - operators, instead of the operator methods. -- Take a `Rad` for `ProjectionFov::fovy`, rather than arbitrary `Angle`s. This - simplifies the signature of `PerspectiveFov` from `PerspectiveFov` to - `PerspectiveFov`. -- The following trait constraints were removed from `Angle`: `Debug`, - `ScalarConv`, `Into>`, `Into>`. -- `Angle` no longer requires `One`, and the implementations have been removed - from `Deg` and `Rad`. This is because angles do not close over multiplication, - and therefore cannot have a multiplicative identity. If we were truly accurate, - `Angle * Angle` would return an `Angle^2` (not supported by the current api). -- Make remainder operators on `Angle`s make sense from the perspective of - dimensional analysis. -- Moved free trigonometric functions onto `Angle`. - -### Removed -- Remove redundant `Point::{min, max}` methods - these are now covered by the - `Array::{min, max}` methods that were introduced in 0.5.0. -- Removed `ToComponents`, `ToComponents2`, and `ToComponents3`. If you were - relying on `ToComponents::decompose`, you can produce the same effect by - accessing the fields on `Decomposed` directly. To create the scale vector, - use: `Vector::from_value(transform.scale)`. -- Removed `CompositeTransform`, `CompositeTransform2`, and `CompositeTransform3`. -- Remove `Vector::one`. Vectors don't really have a multiplicative identity. - If you really want a `one` vector, you can do something like: - `Vector::from_value(1.0)`. -- Remove operator methods from `Vector`, `Matrix`, `Point`, and `Angle` traits - in favor of operator overloading. -- Remove `*_self` methods from `Vector`, `Matrix`, `Point`, and `Angle`. The - operator methods can be used via the unstable assignment operators. -- Remove `#[derive(Hash)]` from `Deg` and `Rad`. This could never really be used - these types, because they expect to be given a `BaseFloat` under normal - circumstances. - -## [v0.6.0] - 2015-12-12 - -### Added -- This CHANGELOG for keeping track of notable changes. -- `Matrix4::{from_scale, from_nonuniform_scale}` for easily constructing - homogeneous scale matrices. - -### Changed -- Renamed `SquareMatrix::one` to `SquareMatrix::identity`. `identity` is easier - to search for, - and the more common name for the multiplicative identity for matrices. -- Matrix impls have now been constrained to `S: BaseFloat`. - -## [v0.5.0] - 2015-11-20 - -### Changed -- Take many point and vector parameters by value. -- Take point and vector operator overloads by value. -- Divide `Matrix` trait into `Matrix` and `SquareMatrix`, opening the door for - non-square matrices in the future. -- Make many trait type parameters associated types. -- Move element-wise methods from `Vector` and `Point` onto the `Array1` trait, - and rename it to `Array`. -- Make pointer access methods on `Array` match the naming scheme of those in the - standard library. - -### Removed -- Removed collision types: `Ray`, `Plane`, `Frustum`, `Aabb2`, `Aabb3` `Obb2`, - `Obb3` `Sphere`, `Cylinder`. These can now be found at - [csherratt/collision-rs](https://github.com/csherratt/collision-rs). -- Remove `Array2` trait, moving methods onto the `Matrix` trait. - -## [v0.4.0] - 2015-10-25 - -## [v0.3.1] - 2015-09-20 - -## [v0.3.0] - 2015-09-20 - -## [v0.2.0] - 2015-05-11 - -## [v0.1.6] - 2015-05-10 - -## [v0.1.5] - 2015-04-25 - -## [v0.1.4] - 2015-04-24 - -## [v0.1.3] - 2015-04-06 - -## [v0.1.2] - 2015-04-01 - -## [v0.1.1] - 2015-03-25 - -## [v0.1.0] - 2015-03-15 - -## [v0.0.8] - 2015-03-09 - -## [v0.0.7] - 2015-03-01 - -## [v0.0.6] - 2015-02-21 - -## [v0.0.5] - 2015-02-16 - -## [v0.0.4] - 2015-02-11 - -## [v0.0.3] - 2015-02-08 - -## v0.0.1 - 2014-06-24 - -[Unreleased]: https://github.com/brendanzab/cgmath/compare/v0.16.1...HEAD -[v0.16.1]: https://github.com/brendanzab/cgmath/compare/v0.16.0...v0.16.1 -[v0.16.0]: https://github.com/brendanzab/cgmath/compare/v0.15.0...v0.16.0 -[v0.15.0]: https://github.com/brendanzab/cgmath/compare/v0.14.1...v0.15.0 -[v0.14.1]: https://github.com/brendanzab/cgmath/compare/v0.14.0...v0.14.1 -[v0.14.0]: https://github.com/brendanzab/cgmath/compare/v0.13.1...v0.14.0 -[v0.13.1]: https://github.com/brendanzab/cgmath/compare/v0.13.0...v0.13.1 -[v0.12.0]: https://github.com/brendanzab/cgmath/compare/v0.12.0...v0.13.0 -[v0.12.0]: https://github.com/brendanzab/cgmath/compare/v0.11.0...v0.12.0 -[v0.11.0]: https://github.com/brendanzab/cgmath/compare/v0.10.0...v0.11.0 -[v0.10.0]: https://github.com/brendanzab/cgmath/compare/v0.9.1...v0.10.0 -[v0.9.1]: https://github.com/brendanzab/cgmath/compare/v0.9.0...v0.9.1 -[v0.9.0]: https://github.com/brendanzab/cgmath/compare/v0.8.0...v0.9.0 -[v0.8.0]: https://github.com/brendanzab/cgmath/compare/v0.7.0...v0.8.0 -[v0.7.0]: https://github.com/brendanzab/cgmath/compare/v0.6.0...v0.7.0 -[v0.6.0]: https://github.com/brendanzab/cgmath/compare/v0.5.0...v0.6.0 -[v0.5.0]: https://github.com/brendanzab/cgmath/compare/v0.4.0...v0.5.0 -[v0.4.0]: https://github.com/brendanzab/cgmath/compare/v0.3.1...v0.4.0 -[v0.3.1]: https://github.com/brendanzab/cgmath/compare/v0.3.0...v0.3.1 -[v0.3.0]: https://github.com/brendanzab/cgmath/compare/v0.2.0...v0.3.0 -[v0.2.0]: https://github.com/brendanzab/cgmath/compare/v0.1.6...v0.2.0 -[v0.1.6]: https://github.com/brendanzab/cgmath/compare/v0.1.5...v0.1.6 -[v0.1.5]: https://github.com/brendanzab/cgmath/compare/v0.1.4...v0.1.5 -[v0.1.4]: https://github.com/brendanzab/cgmath/compare/v0.1.3...v0.1.4 -[v0.1.3]: https://github.com/brendanzab/cgmath/compare/v0.1.2...v0.1.3 -[v0.1.2]: https://github.com/brendanzab/cgmath/compare/v0.1.1...v0.1.2 -[v0.1.1]: https://github.com/brendanzab/cgmath/compare/v0.1.0...v0.1.1 -[v0.1.0]: https://github.com/brendanzab/cgmath/compare/v0.0.8...v0.1.0 -[v0.0.8]: https://github.com/brendanzab/cgmath/compare/v0.0.7...v0.0.8 -[v0.0.7]: https://github.com/brendanzab/cgmath/compare/v0.0.6...v0.0.7 -[v0.0.6]: https://github.com/brendanzab/cgmath/compare/v0.0.5...v0.0.6 -[v0.0.5]: https://github.com/brendanzab/cgmath/compare/v0.0.4...v0.0.5 -[v0.0.4]: https://github.com/brendanzab/cgmath/compare/v0.0.3...v0.0.4 -[v0.0.3]: https://github.com/brendanzab/cgmath/compare/v0.0.1...v0.0.3 diff --git a/third_party/cargo/vendor/cgmath-0.17.0/Cargo.toml b/third_party/cargo/vendor/cgmath-0.17.0/Cargo.toml deleted file mode 100644 index b571b40..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/Cargo.toml +++ /dev/null @@ -1,56 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "cgmath" -version = "0.17.0" -authors = ["Brendan Zabarauskas "] -description = "A linear algebra and mathematics library for computer graphics." -homepage = "https://github.com/brendanzab/cgmath" -documentation = "https://docs.rs/cgmath" -readme = "README.md" -keywords = ["gamedev", "math", "matrix", "vector", "quaternion"] -license = "Apache-2.0" -repository = "https://github.com/brendanzab/cgmath" - -[lib] -name = "cgmath" -[dependencies.approx] -version = "0.3" - -[dependencies.mint] -version = "0.5" -optional = true - -[dependencies.num-traits] -version = "0.2" - -[dependencies.rand] -version = "0.6" - -[dependencies.serde] -version = "1.0" -features = ["serde_derive"] -optional = true - -[dependencies.simd] -version = "0.2" -optional = true -[dev-dependencies.glium] -version = "0.23" - -[dev-dependencies.serde_json] -version = "1.0" - -[features] -swizzle = [] -unstable = [] diff --git a/third_party/cargo/vendor/cgmath-0.17.0/README.md b/third_party/cargo/vendor/cgmath-0.17.0/README.md deleted file mode 100755 index d5f8b8e..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# cgmath-rs - -[![Build Status](https://travis-ci.org/brendanzab/cgmath.svg?branch=master)](https://travis-ci.org/brendanzab/cgmath) -[![Documentation](https://docs.rs/cgmath/badge.svg)](https://docs.rs/cgmath) -[![Version](https://img.shields.io/crates/v/cgmath.svg)](https://crates.io/crates/cgmath) -[![License](https://img.shields.io/crates/l/cgmath.svg)](https://github.com/brendanzab/cgmath/blob/master/LICENSE) -[![Downloads](https://img.shields.io/crates/d/cgmath.svg)](https://crates.io/crates/cgmath) -[![Gitter](https://badges.gitter.im/brendanzab/cgmath.svg)](https://gitter.im/brendanzab/cgmath) - -A linear algebra and mathematics library for computer graphics. - -The library provides: - -- vectors: `Vector2`, `Vector3`, `Vector4` -- square matrices: `Matrix2`, `Matrix3`, `Matrix4` -- a quaternion type: `Quaternion` -- rotation matrices: `Basis2`, `Basis3` -- angle units: `Rad`, `Deg` -- points: `Point2`, `Point3` -- perspective projections: `Perspective`, `PerspectiveFov`, `Ortho` -- spatial transformations: `AffineMatrix3`, `Transform3` - -Not all of the functionality has been implemented yet, and the existing code -is not fully covered by the testsuite. If you encounter any mistakes or -omissions please let me know by posting an issue, or even better: send me a -pull request with a fix. - -## Conventions - -cgmath interprets its vectors as column matrices (also known as "column -vectors"), meaning when transforming a vector with a matrix, the matrix goes -on the left. This is reflected in the fact that cgmath implements the -multiplication operator for Matrix * Vector, but not Vector * Matrix. - -## Features - -### Swizzling -This library offers an optional feature called -["swizzling"](https://en.wikipedia.org/wiki/Swizzling_(computer_graphics)) -widely familiar to GPU programmers. To enable swizzle operators, pass the -`--features="swizzle"` option to cargo. Enabling this feature will increase -the size of the cgmath library by approximately 0.6MB. This isn't an -issue if the library is linked in the "normal" way by adding cgmath as a -dependency in Cargo.toml, which will link cgmath statically so all unused -swizzle operators will be optimized away by the compiler in release mode. - -#### Example -If we have -```rust -let v = Vector3::new(1.0, 2.0, 3.0); -``` -then `v.xyxz()` produces a -```rust -Vector4 { x: 1.0, y: 2.0, z: 1.0, w: 3.0 } -``` -and `v.zy()` produces a -```rust -Vector2 { x: 3.0, y: 2.0 } -``` - -## Limitations - -cgmath is _not_ an n-dimensional library and is aimed at computer graphics -applications rather than general linear algebra. It only offers the 2, 3, and -4 dimensional structures that are more than enough for most computer graphics -applications. This design decision was made in order to simplify the -implementation (Rust cannot parameterize over constants at compile time), and to -make dimension-specific optimisations easier in the future. - -## Contributing - -Pull requests are most welcome, especially in the realm of performance -enhancements and fixing any mistakes I may have made along the way. Unit tests -and benchmarks are also required, so help on that front would be most -appreciated. - -## Support - -Contact `bjz` on irc.mozilla.org [#rust](http://mibbit.com/?server=irc.mozilla.org&channel=%23rust) -and [#rust-gamedev](http://mibbit.com/?server=irc.mozilla.org&channel=%23rust-gamedev), -or [post an issue](https://github.com/bjz/cgmath/issues/new) on Github. diff --git a/third_party/cargo/vendor/cgmath-0.17.0/benches/common/macros.rs b/third_party/cargo/vendor/cgmath-0.17.0/benches/common/macros.rs deleted file mode 100755 index 265a1af..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/benches/common/macros.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -macro_rules! bench_binop { - ($name: ident, $t1: ty, $t2: ty, $binop: ident) => { - #[bench] - fn $name(bh: &mut Bencher) { - const LEN: usize = 1 << 13; - - let mut rng = IsaacRng::from_entropy(); - - let elems1: Vec<$t1> = (0..LEN).map(|_| rng.gen::<$t1>()).collect(); - let elems2: Vec<$t2> = (0..LEN).map(|_| rng.gen::<$t2>()).collect(); - let mut i = 0; - - bh.iter(|| { - i = (i + 1) & (LEN - 1); - - unsafe { - test::black_box(elems1.get_unchecked(i).$binop(*elems2.get_unchecked(i))) - } - }) - } - }; -} - -macro_rules! bench_unop { - ($name: ident, $t: ty, $unop: ident) => { - #[bench] - fn $name(bh: &mut Bencher) { - const LEN: usize = 1 << 13; - - let mut rng = IsaacRng::from_entropy(); - - let mut elems: Vec<$t> = (0..LEN).map(|_| rng.gen::<$t>()).collect(); - let mut i = 0; - - bh.iter(|| { - i = (i + 1) & (LEN - 1); - - unsafe { - test::black_box(elems.get_unchecked_mut(i).$unop()) - } - }) - } - }; -} - -macro_rules! bench_construction { - ($name: ident, $t: ty, $constructor: path [ $($args: ident: $types: ty),+ ]) => { - #[bench] - fn $name(bh: &mut Bencher) { - const LEN: usize = 1 << 13; - - let mut rng = IsaacRng::from_entropy(); - - $(let $args: Vec<$types> = (0..LEN).map(|_| rng.gen::<$types>()).collect();)* - let mut i = 0; - - bh.iter(|| { - i = (i + 1) & (LEN - 1); - - unsafe { - let res: $t = $constructor($(*$args.get_unchecked(i),)*); - test::black_box(res) - } - }) - } - }; -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/benches/vec.rs b/third_party/cargo/vendor/cgmath-0.17.0/benches/vec.rs deleted file mode 100755 index c1e62d6..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/benches/vec.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![feature(test)] -#![allow(unused_macros)] - -extern crate cgmath; -extern crate rand; -extern crate test; - -use rand::{IsaacRng, Rng, FromEntropy}; -use std::ops::*; -use test::Bencher; - -use cgmath::*; - -#[path = "common/macros.rs"] -#[macro_use] -mod macros; - -bench_binop!(_bench_vector2_add_v, Vector2, Vector2, add); -bench_binop!(_bench_vector3_add_v, Vector3, Vector3, add); -bench_binop!(_bench_vector4_add_v, Vector4, Vector4, add); - -bench_binop!(_bench_vector2_sub_v, Vector2, Vector2, sub); -bench_binop!(_bench_vector3_sub_v, Vector3, Vector3, sub); -bench_binop!(_bench_vector4_sub_v, Vector4, Vector4, sub); - -bench_binop!(_bench_vector2_mul_s, Vector2, f32, mul); -bench_binop!(_bench_vector3_mul_s, Vector3, f32, mul); -bench_binop!(_bench_vector4_mul_s, Vector4, f32, mul); - -bench_binop!(_bench_vector2_div_s, Vector2, f32, div); -bench_binop!(_bench_vector3_div_s, Vector3, f32, div); -bench_binop!(_bench_vector4_div_s, Vector4, f32, div); - -bench_binop!(_bench_vector2_rem_s, Vector2, f32, rem); -bench_binop!(_bench_vector3_rem_s, Vector3, f32, rem); -bench_binop!(_bench_vector4_rem_s, Vector4, f32, rem); - -bench_binop!(_bench_vector2_dot, Vector2, Vector2, dot); -bench_binop!(_bench_vector3_dot, Vector3, Vector3, dot); -bench_binop!(_bench_vector4_dot, Vector4, Vector4, dot); - -bench_binop!(_bench_vector3_cross, Vector3, Vector3, cross); - -bench_unop!(_bench_vector2_magnitude, Vector2, magnitude); -bench_unop!(_bench_vector3_magnitude, Vector3, magnitude); -bench_unop!(_bench_vector4_magnitude, Vector4, magnitude); - -bench_unop!(_bench_vector2_normalize, Vector2, normalize); -bench_unop!(_bench_vector3_normalize, Vector3, normalize); -bench_unop!(_bench_vector4_normalize, Vector4, normalize); diff --git a/third_party/cargo/vendor/cgmath-0.17.0/build.rs b/third_party/cargo/vendor/cgmath-0.17.0/build.rs deleted file mode 100755 index 2f53369..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/build.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::fs::File; -use std::io::Write; -use std::path::Path; -use std::env; -use std::string::String; - -/// Generate the name of the swizzle function and what it returns. -/// NOTE: This function assumes that variables are in ASCII format -#[cfg(feature = "swizzle")] -fn gen_swizzle_nth<'a>(variables: &'a str, mut i: usize, upto: usize) -> Option<(String, String)> { - debug_assert!(i > 0); // zeroth permutation is empty - let mut swizzle_impl = String::new(); - let mut swizzle = String::new(); - let n = variables.len()+1; - for _ in 0..upto { - if i == 0 { break; } - if i % n == 0 { return None; } - let c = variables.as_bytes()[i%n - 1] as char; - swizzle.push(c); - swizzle_impl.push_str(&format!("self.{}, ", c)); - i = i/n; - } - Some((swizzle, swizzle_impl)) -} - -/// A function that generates swizzle functions as a string. -/// `variables`: swizzle variables (e.g. "xyz") -/// `upto`: largest output vector size (e.g. for `variables = "xy"` and `upto = 4`, `xyxy()` is a -/// valid swizzle operator. -/// NOTE: This function assumes that variables are in ASCII format -#[cfg(feature = "swizzle")] -fn gen_swizzle_functions(variables: &'static str, upto: usize) -> String { - let mut result = String::new(); - let nn = (variables.len()+1).pow(upto as u32); - for i in 1..nn { - if let Some((swizzle_name, swizzle_impl)) = gen_swizzle_nth(variables, i, upto) { - let dim = format!("{}", swizzle_name.len()); - result.push_str( - &format!(" - /// Swizzle operator that creates a new type with dimension {2} from variables `{0}`. - #[inline] pub fn {0}(&self) -> $vector_type{2}<$S> {{ $vector_type{2}::new({1}) }}\n", - swizzle_name, swizzle_impl, dim)); - } - } - result -} - -#[cfg(not(feature = "swizzle"))] -fn gen_swizzle_functions(_: &'static str, _: usize) -> String { - String::new() -} - - -/// This script generates the macro for building swizzle operators for multidimensional -/// vectors and points. This macro is included in macros.rs -fn main() { - // save the file to output directory - let out_dir = env::var("OUT_DIR").unwrap(); - let swizzle_file_path = Path::new(&out_dir).join("swizzle_operator_macro.rs"); - - // This is the string representing the generated macro - let data = format!( -"/// Generate glm/glsl style swizzle operators -macro_rules! impl_swizzle_functions {{ - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $S:ident, x) => {{ -{x3} - }}; - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $S:ident, xy) => {{ -{xy3} - }}; - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $S:ident, xyz) => {{ -{xyz3} - }}; - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, x) => {{ -{x4} - }}; - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, xy) => {{ -{xy4} - }}; - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, xyz) => {{ -{xyz4} - }}; - ($vector_type1:ident, $vector_type2:ident, $vector_type3:ident, $vector_type4:ident, $S:ident, xyzw) => {{ -{xyzw4} - }}; -}}", x3 = gen_swizzle_functions("x", 3), - xy3 = gen_swizzle_functions("xy", 3), - xyz3 = gen_swizzle_functions("xyz", 3), - x4 = gen_swizzle_functions("x", 4), - xy4 = gen_swizzle_functions("xy", 4), - xyz4 = gen_swizzle_functions("xyz", 4), - xyzw4 = gen_swizzle_functions("xyzw", 4)); - let mut f = File::create(swizzle_file_path) - .expect("Unable to create file that defines the swizzle operator macro."); - f.write_all(data.as_bytes()).expect("Unable to write swizzle operator macro."); -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/lib.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/lib.rs deleted file mode 100755 index a1f7b45..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/lib.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! A low-dimensional linear algebra library, targeted at computer graphics. -//! -//! # Trait overview -//! -//! In order to make a clean, composable API, we divide operations into traits -//! that are roughly based on mathematical properties. The main ones that we -//! concern ourselves with are listed below: -//! -//! - `VectorSpace`: Specifies the main operators for vectors, quaternions, and -//! matrices. -//! - `MetricSpace`: For types that have a distance function implemented. -//! - `InnerSpace`: For types that have a dot (or inner) product - ie. vectors or -//! quaternions. This also allows for the definition of operations that are -//! based on the dot product, like finding the magnitude or normalizing. -//! - `EuclideanSpace`: Points in euclidean space, with an associated space of -//! displacement vectors. -//! - `Matrix`: Common operations for matrices of arbitrary dimensions. -//! - `SquareMatrix`: A special trait for matrices where the number of columns -//! equal the number of rows. -//! -//! Other traits are included for practical convenience, for example: -//! -//! - `Array`: For contiguous, indexable arrays of elements, specifically -//! vectors. -//! - `ElementWise`: For element-wise addition, subtraction, multiplication, -//! division, and remainder operations. -//! -//! # The prelude -//! -//! Importing each trait individually can become a chore, so we provide a -//! `prelude` module to allow you to import the main trait all at once. For -//! example: -//! -//! ```rust -//! use cgmath::prelude::*; -//! ``` - -#![cfg_attr(feature = "simd", feature(specialization))] - -#[macro_use] -extern crate approx; - -#[cfg(feature = "mint")] -pub extern crate mint; - -extern crate rand; -pub extern crate num_traits; - -#[cfg(feature = "serde")] -#[macro_use] -extern crate serde; - -#[cfg(feature = "simd")] -extern crate simd; - -// Re-exports - -pub use approx::*; -pub use num::*; -pub use structure::*; - -pub use matrix::{Matrix2, Matrix3, Matrix4}; -pub use quaternion::Quaternion; -pub use vector::{dot, Vector1, Vector2, Vector3, Vector4, vec1, vec2, vec3, vec4}; - -pub use angle::{Deg, Rad}; -pub use euler::Euler; -pub use point::{Point1, Point2, Point3}; -pub use rotation::*; -pub use transform::*; - -pub use projection::*; - -// Modules - -pub mod conv; -pub mod prelude; - -mod macros; - -mod num; -mod structure; - -mod matrix; -mod quaternion; -mod vector; - -mod angle; -mod euler; -mod point; -mod rotation; -mod transform; - -mod projection; diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/macros.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/macros.rs deleted file mode 100755 index 573c597..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/macros.rs +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Utility macros for code generation - -#![macro_use] - -/// Generates a binary operator implementation for the permutations of by-ref and by-val -macro_rules! impl_operator { - // When it is an unary operator - (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty { - fn $op:ident($x:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op for $Lhs { - type Output = $Output; - #[inline] - fn $op(self) -> $Output { - let $x = self; $body - } - } - - impl<'a, $S: $Constraint> $Op for &'a $Lhs { - type Output = $Output; - #[inline] - fn $op(self) -> $Output { - let $x = self; $body - } - } - }; - // When the right operand is a scalar - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the right operand is a compound type - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the left operand is a scalar - ($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl $Op<$Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - fn $op(self, other: &'a $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; -} - -macro_rules! impl_assignment_operator { - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block - }) => { - impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { - #[inline] - fn $op(&mut $lhs, $rhs: $Rhs) $body - } - }; -} - -macro_rules! fold_array { - (&$method:ident, { $x:expr }) => { *$x }; - (&$method:ident, { $x:expr, $y:expr }) => { $x.$method(&$y) }; - (&$method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method(&$y).$method(&$z) }; - (&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method(&$y).$method(&$z).$method(&$w) }; - ($method:ident, { $x:expr }) => { $x }; - ($method:ident, { $x:expr, $y:expr }) => { $x.$method($y) }; - ($method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method($y).$method($z) }; - ($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method($y).$method($z).$method($w) }; -} - -/// Generate array conversion implementations for a compound array type -macro_rules! impl_fixed_array_conversions { - ($ArrayN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { - impl<$S> Into<[$S; $n]> for $ArrayN<$S> { - #[inline] - fn into(self) -> [$S; $n] { - match self { $ArrayN { $($field),+ } => [$($field),+] } - } - } - - impl<$S> AsRef<[$S; $n]> for $ArrayN<$S> { - #[inline] - fn as_ref(&self) -> &[$S; $n] { - unsafe { mem::transmute(self) } - } - } - - impl<$S> AsMut<[$S; $n]> for $ArrayN<$S> { - #[inline] - fn as_mut(&mut self) -> &mut [$S; $n] { - unsafe { mem::transmute(self) } - } - } - - impl<$S: Clone> From<[$S; $n]> for $ArrayN<$S> { - #[inline] - fn from(v: [$S; $n]) -> $ArrayN<$S> { - // We need to use a clone here because we can't pattern match on arrays yet - $ArrayN { $($field: v[$index].clone()),+ } - } - } - - impl<'a, $S> From<&'a [$S; $n]> for &'a $ArrayN<$S> { - #[inline] - fn from(v: &'a [$S; $n]) -> &'a $ArrayN<$S> { - unsafe { mem::transmute(v) } - } - } - - impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $ArrayN<$S> { - #[inline] - fn from(v: &'a mut [$S; $n]) -> &'a mut $ArrayN<$S> { - unsafe { mem::transmute(v) } - } - } - } -} - -/// Generate homogeneous tuple conversion implementations for a compound array type -macro_rules! impl_tuple_conversions { - ($ArrayN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => { - impl<$S> Into<$Tuple> for $ArrayN<$S> { - #[inline] - fn into(self) -> $Tuple { - match self { $ArrayN { $($field),+ } => ($($field),+,) } - } - } - - impl<$S> AsRef<$Tuple> for $ArrayN<$S> { - #[inline] - fn as_ref(&self) -> &$Tuple { - unsafe { mem::transmute(self) } - } - } - - impl<$S> AsMut<$Tuple> for $ArrayN<$S> { - #[inline] - fn as_mut(&mut self) -> &mut $Tuple { - unsafe { mem::transmute(self) } - } - } - - impl<$S> From<$Tuple> for $ArrayN<$S> { - #[inline] - fn from(v: $Tuple) -> $ArrayN<$S> { - match v { ($($field),+,) => $ArrayN { $($field: $field),+ } } - } - } - - impl<'a, $S> From<&'a $Tuple> for &'a $ArrayN<$S> { - #[inline] - fn from(v: &'a $Tuple) -> &'a $ArrayN<$S> { - unsafe { mem::transmute(v) } - } - } - - impl<'a, $S> From<&'a mut $Tuple> for &'a mut $ArrayN<$S> { - #[inline] - fn from(v: &'a mut $Tuple) -> &'a mut $ArrayN<$S> { - unsafe { mem::transmute(v) } - } - } - } -} - -/// Generates index operators for a compound type -macro_rules! impl_index_operators { - ($VectorN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { - impl<$S> Index<$I> for $VectorN<$S> { - type Output = $Output; - - #[inline] - fn index<'a>(&'a self, i: $I) -> &'a $Output { - let v: &[$S; $n] = self.as_ref(); &v[i] - } - } - - impl<$S> IndexMut<$I> for $VectorN<$S> { - #[inline] - fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { - let v: &mut [$S; $n] = self.as_mut(); &mut v[i] - } - } - } -} - -#[cfg(feature = "simd")] -macro_rules! impl_operator_default { - // When it is an unary operator - (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty { - fn $op:ident($x:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self) -> $Output { - let $x = self; $body - } - } - - impl<'a, $S: $Constraint> $Op for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self) -> $Output { - let $x = self; $body - } - } - }; - // When the right operand is a scalar - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the right operand is a compound type - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl<$S: $Constraint> $Op<$Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; - // When the left operand is a scalar - ($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl $Op<$Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - - impl<'a> $Op<&'a $Rhs<$S>> for $Lhs { - type Output = $Output; - #[inline] - default fn $op(self, other: &'a $Rhs<$S>) -> $Output { - let ($lhs, $rhs) = (self, other); $body - } - } - }; -} - -#[cfg(feature = "simd")] -macro_rules! impl_assignment_operator_default { - (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block - }) => { - impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs { - #[inline] - default fn $op(&mut $lhs, $rhs: $Rhs) $body - } - }; -} - -/// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd -#[cfg(feature = "simd")] -macro_rules! impl_operator_simd { - // When it is an unary operator - ([$Simd:ident]; $Op:ident for $Lhs:ty { - fn $op:ident($x:ident) -> $Output:ty { $body:expr } - }) => { - - impl $Op for $Lhs { - #[inline] - fn $op(self) -> $Output { - let $x: $Simd = self.into(); $body - } - } - }; - // When the right operand is a scalar - (@rs [$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl $Op<$Rhs> for $Lhs { - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), $Simd::splat(other)); $body - } - } - - - impl<'a> $Op<$Rhs> for &'a $Lhs { - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), $Simd::splat(other)); $body - } - } - }; - - // When the right operand is a compound type - ([$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - - impl $Op<$Rhs> for $Lhs { - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), other.into()); $body - } - } - - - impl<'a> $Op<&'a $Rhs> for $Lhs { - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), (*other).into()); $body - } - } - - impl<'a> $Op<$Rhs> for &'a $Lhs { - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), other.into()); $body - } - } - - impl<'a, 'b> $Op<&'a $Rhs> for &'b $Lhs { - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), (*other).into()); $body - } - } - }; - - // When the left operand is a scalar - (@ls [$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ident { - fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } - }) => { - impl $Op<$Rhs> for $Lhs { - #[inline] - fn $op(self, other: $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), other.into()); $body - } - } - - impl<'a> $Op<&'a $Rhs> for $Lhs { - #[inline] - fn $op(self, other: &'a $Rhs) -> $Output { - let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), (*other).into()); $body - } - } - }; -} - -/// Generate `mint` types conversion implementations -#[cfg(feature = "mint")] -macro_rules! impl_mint_conversions { - ($ArrayN:ident { $($field:ident),+ }, $Mint:ident) => { - impl Into> for $ArrayN { - #[inline] - fn into(self) -> mint::$Mint { - mint::$Mint::from([$(self.$field),+]) - } - } - - impl From> for $ArrayN { - #[inline] - fn from(v: mint::$Mint) -> Self { - $ArrayN { $( $field: v.$field, )+ } - } - } - } -} - -include!(concat!(env!("OUT_DIR"), "/swizzle_operator_macro.rs")); diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/matrix.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/matrix.rs deleted file mode 100755 index 3219b1b..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/matrix.rs +++ /dev/null @@ -1,1651 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use rand::distributions::{Standard, Distribution}; -use rand::Rng; -use num_traits::{cast, NumCast}; -use std::fmt; -use std::iter; -use std::mem; -use std::ops::*; -use std::ptr; - -use structure::*; - -use angle::Rad; -use approx; -use euler::Euler; -use num::BaseFloat; -use point::{Point2, Point3}; -use quaternion::Quaternion; -use transform::{Transform, Transform2, Transform3}; -use vector::{Vector2, Vector3, Vector4}; - -#[cfg(feature = "mint")] -use mint; - -/// A 2 x 2, column major matrix -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(Copy, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Matrix2 { - /// The first column of the matrix. - pub x: Vector2, - /// The second column of the matrix. - pub y: Vector2, -} - -/// A 3 x 3, column major matrix -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(Copy, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Matrix3 { - /// The first column of the matrix. - pub x: Vector3, - /// The second column of the matrix. - pub y: Vector3, - /// The third column of the matrix. - pub z: Vector3, -} - -/// A 4 x 4, column major matrix -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(Copy, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Matrix4 { - /// The first column of the matrix. - pub x: Vector4, - /// The second column of the matrix. - pub y: Vector4, - /// The third column of the matrix. - pub z: Vector4, - /// The fourth column of the matrix. - pub w: Vector4, -} - -impl Matrix2 { - /// Create a new matrix, providing values for each index. - #[inline] - pub const fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2 { - Matrix2::from_cols(Vector2::new(c0r0, c0r1), Vector2::new(c1r0, c1r1)) - } - - /// Create a new matrix, providing columns. - #[inline] - pub const fn from_cols(c0: Vector2, c1: Vector2) -> Matrix2 { - Matrix2 { x: c0, y: c1 } - } -} - -impl Matrix2 { - /// Create a transformation matrix that will cause a vector to point at - /// `dir`, using `up` for orientation. - pub fn look_at(dir: Vector2, up: Vector2) -> Matrix2 { - //TODO: verify look_at 2D - Matrix2::from_cols(up, dir).transpose() - } - - #[inline] - pub fn from_angle>>(theta: A) -> Matrix2 { - let (s, c) = Rad::sin_cos(theta.into()); - - Matrix2::new(c, s, -s, c) - } - - /// Are all entries in the matrix finite. - pub fn is_finite(&self) -> bool { - self.x.is_finite() && self.y.is_finite() - } -} - -impl Matrix3 { - /// Create a new matrix, providing values for each index. - #[inline] - #[cfg_attr(rustfmt, rustfmt_skip)] - pub const fn new( - c0r0:S, c0r1:S, c0r2:S, - c1r0:S, c1r1:S, c1r2:S, - c2r0:S, c2r1:S, c2r2:S, - ) -> Matrix3 { - Matrix3::from_cols( - Vector3::new(c0r0, c0r1, c0r2), - Vector3::new(c1r0, c1r1, c1r2), - Vector3::new(c2r0, c2r1, c2r2), - ) - } - - /// Create a new matrix, providing columns. - #[inline] - pub const fn from_cols(c0: Vector3, c1: Vector3, c2: Vector3) -> Matrix3 { - Matrix3 { - x: c0, - y: c1, - z: c2, - } - } -} - -impl Matrix3 { - /// Create a rotation matrix that will cause a vector to point at - /// `dir`, using `up` for orientation. - pub fn look_at(dir: Vector3, up: Vector3) -> Matrix3 { - let dir = dir.normalize(); - let side = up.cross(dir).normalize(); - let up = dir.cross(side).normalize(); - - Matrix3::from_cols(side, up, dir).transpose() - } - - /// Create a rotation matrix from a rotation around the `x` axis (pitch). - pub fn from_angle_x>>(theta: A) -> Matrix3 { - // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = Rad::sin_cos(theta.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - S::one(), S::zero(), S::zero(), - S::zero(), c, s, - S::zero(), -s, c, - ) - } - - /// Create a rotation matrix from a rotation around the `y` axis (yaw). - pub fn from_angle_y>>(theta: A) -> Matrix3 { - // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = Rad::sin_cos(theta.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - c, S::zero(), -s, - S::zero(), S::one(), S::zero(), - s, S::zero(), c, - ) - } - - /// Create a rotation matrix from a rotation around the `z` axis (roll). - pub fn from_angle_z>>(theta: A) -> Matrix3 { - // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = Rad::sin_cos(theta.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - c, s, S::zero(), - -s, c, S::zero(), - S::zero(), S::zero(), S::one(), - ) - } - - /// Create a rotation matrix from an angle around an arbitrary axis. - /// - /// The specified axis **must be normalized**, or it represents an invalid rotation. - pub fn from_axis_angle>>(axis: Vector3, angle: A) -> Matrix3 { - let (s, c) = Rad::sin_cos(angle.into()); - let _1subc = S::one() - c; - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - _1subc * axis.x * axis.x + c, - _1subc * axis.x * axis.y + s * axis.z, - _1subc * axis.x * axis.z - s * axis.y, - - _1subc * axis.x * axis.y - s * axis.z, - _1subc * axis.y * axis.y + c, - _1subc * axis.y * axis.z + s * axis.x, - - _1subc * axis.x * axis.z + s * axis.y, - _1subc * axis.y * axis.z - s * axis.x, - _1subc * axis.z * axis.z + c, - ) - } - - /// Are all entries in the matrix finite. - pub fn is_finite(&self) -> bool { - self.x.is_finite() && self.y.is_finite() && self.z.is_finite() - } -} - -impl Matrix4 { - /// Create a new matrix, providing values for each index. - #[inline] - #[cfg_attr(rustfmt, rustfmt_skip)] - pub const fn new( - c0r0: S, c0r1: S, c0r2: S, c0r3: S, - c1r0: S, c1r1: S, c1r2: S, c1r3: S, - c2r0: S, c2r1: S, c2r2: S, c2r3: S, - c3r0: S, c3r1: S, c3r2: S, c3r3: S, - ) -> Matrix4 { - Matrix4::from_cols( - Vector4::new(c0r0, c0r1, c0r2, c0r3), - Vector4::new(c1r0, c1r1, c1r2, c1r3), - Vector4::new(c2r0, c2r1, c2r2, c2r3), - Vector4::new(c3r0, c3r1, c3r2, c3r3), - ) - } - - /// Create a new matrix, providing columns. - #[inline] - pub const fn from_cols(c0: Vector4, c1: Vector4, c2: Vector4, c3: Vector4) -> Matrix4 { - Matrix4 { - x: c0, - y: c1, - z: c2, - w: c3, - } - } -} - -impl Matrix4 { - /// Create a homogeneous transformation matrix from a translation vector. - #[inline] - pub fn from_translation(v: Vector3) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - S::one(), S::zero(), S::zero(), S::zero(), - S::zero(), S::one(), S::zero(), S::zero(), - S::zero(), S::zero(), S::one(), S::zero(), - v.x, v.y, v.z, S::one(), - ) - } - - /// Create a homogeneous transformation matrix from a scale value. - #[inline] - pub fn from_scale(value: S) -> Matrix4 { - Matrix4::from_nonuniform_scale(value, value, value) - } - - /// Create a homogeneous transformation matrix from a set of scale values. - #[inline] - pub fn from_nonuniform_scale(x: S, y: S, z: S) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - x, S::zero(), S::zero(), S::zero(), - S::zero(), y, S::zero(), S::zero(), - S::zero(), S::zero(), z, S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } - - /// Create a homogeneous transformation matrix that will cause a vector to point at - /// `dir`, using `up` for orientation. - pub fn look_at_dir(eye: Point3, dir: Vector3, up: Vector3) -> Matrix4 { - let f = dir.normalize(); - let s = f.cross(up).normalize(); - let u = s.cross(f); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(), - s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(), - s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(), - -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(), - ) - } - - /// Create a homogeneous transformation matrix that will cause a vector to point at - /// `center`, using `up` for orientation. - pub fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { - Matrix4::look_at_dir(eye, center - eye, up) - } - - /// Create a homogeneous transformation matrix from a rotation around the `x` axis (pitch). - pub fn from_angle_x>>(theta: A) -> Matrix4 { - // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = Rad::sin_cos(theta.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - S::one(), S::zero(), S::zero(), S::zero(), - S::zero(), c, s, S::zero(), - S::zero(), -s, c, S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } - - /// Create a homogeneous transformation matrix from a rotation around the `y` axis (yaw). - pub fn from_angle_y>>(theta: A) -> Matrix4 { - // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = Rad::sin_cos(theta.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - c, S::zero(), -s, S::zero(), - S::zero(), S::one(), S::zero(), S::zero(), - s, S::zero(), c, S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } - - /// Create a homogeneous transformation matrix from a rotation around the `z` axis (roll). - pub fn from_angle_z>>(theta: A) -> Matrix4 { - // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = Rad::sin_cos(theta.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - c, s, S::zero(), S::zero(), - -s, c, S::zero(), S::zero(), - S::zero(), S::zero(), S::one(), S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } - - /// Create a homogeneous transformation matrix from an angle around an arbitrary axis. - /// - /// The specified axis **must be normalized**, or it represents an invalid rotation. - pub fn from_axis_angle>>(axis: Vector3, angle: A) -> Matrix4 { - let (s, c) = Rad::sin_cos(angle.into()); - let _1subc = S::one() - c; - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - _1subc * axis.x * axis.x + c, - _1subc * axis.x * axis.y + s * axis.z, - _1subc * axis.x * axis.z - s * axis.y, - S::zero(), - - _1subc * axis.x * axis.y - s * axis.z, - _1subc * axis.y * axis.y + c, - _1subc * axis.y * axis.z + s * axis.x, - S::zero(), - - _1subc * axis.x * axis.z + s * axis.y, - _1subc * axis.y * axis.z - s * axis.x, - _1subc * axis.z * axis.z + c, - S::zero(), - - S::zero(), S::zero(), S::zero(), S::one(), - ) - } - - /// Are all entries in the matrix finite. - pub fn is_finite(&self) -> bool { - self.w.is_finite() && self.x.is_finite() && self.y.is_finite() && self.z.is_finite() - } -} - -impl Zero for Matrix2 { - #[inline] - fn zero() -> Matrix2 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix2::new( - S::zero(), S::zero(), - S::zero(), S::zero(), - ) - } - - #[inline] - fn is_zero(&self) -> bool { - ulps_eq!(self, &Self::zero()) - } -} - -impl Zero for Matrix3 { - #[inline] - fn zero() -> Matrix3 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), - ) - } - - #[inline] - fn is_zero(&self) -> bool { - ulps_eq!(self, &Self::zero()) - } -} - -impl Zero for Matrix4 { - #[inline] - fn zero() -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - S::zero(), S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), S::zero(), - S::zero(), S::zero(), S::zero(), S::zero(), - ) - } - - #[inline] - fn is_zero(&self) -> bool { - ulps_eq!(self, &Self::zero()) - } -} - -impl One for Matrix2 { - #[inline] - fn one() -> Matrix2 { - Matrix2::from_value(S::one()) - } -} - -impl One for Matrix3 { - #[inline] - fn one() -> Matrix3 { - Matrix3::from_value(S::one()) - } -} - -impl One for Matrix4 { - #[inline] - fn one() -> Matrix4 { - Matrix4::from_value(S::one()) - } -} - -impl VectorSpace for Matrix2 { - type Scalar = S; -} - -impl VectorSpace for Matrix3 { - type Scalar = S; -} - -impl VectorSpace for Matrix4 { - type Scalar = S; -} - -impl Matrix for Matrix2 { - type Column = Vector2; - type Row = Vector2; - type Transpose = Matrix2; - - #[inline] - fn row(&self, r: usize) -> Vector2 { - Vector2::new(self[0][r], self[1][r]) - } - - #[inline] - fn swap_rows(&mut self, a: usize, b: usize) { - self[0].swap_elements(a, b); - self[1].swap_elements(a, b); - } - - #[inline] - fn swap_columns(&mut self, a: usize, b: usize) { - unsafe { ptr::swap(&mut self[a], &mut self[b]) }; - } - - #[inline] - fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) { - let (ac, ar) = a; - let (bc, br) = b; - unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; - } - - fn transpose(&self) -> Matrix2 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix2::new( - self[0][0], self[1][0], - self[0][1], self[1][1], - ) - } -} - -impl SquareMatrix for Matrix2 { - type ColumnRow = Vector2; - - #[inline] - fn from_value(value: S) -> Matrix2 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix2::new( - value, S::zero(), - S::zero(), value, - ) - } - - #[inline] - fn from_diagonal(value: Vector2) -> Matrix2 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix2::new( - value.x, S::zero(), - S::zero(), value.y, - ) - } - - #[inline] - fn transpose_self(&mut self) { - self.swap_elements((0, 1), (1, 0)); - } - - #[inline] - fn determinant(&self) -> S { - self[0][0] * self[1][1] - self[1][0] * self[0][1] - } - - #[inline] - fn diagonal(&self) -> Vector2 { - Vector2::new(self[0][0], self[1][1]) - } - - #[inline] - fn invert(&self) -> Option> { - let det = self.determinant(); - if det == S::zero() { - None - } else { - #[cfg_attr(rustfmt, rustfmt_skip)] - Some(Matrix2::new( - self[1][1] / det, -self[0][1] / det, - -self[1][0] / det, self[0][0] / det, - )) - } - } - - #[inline] - fn is_diagonal(&self) -> bool { - ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero()) - } - - #[inline] - fn is_symmetric(&self) -> bool { - ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[1][0], &self[0][1]) - } -} - -impl Matrix for Matrix3 { - type Column = Vector3; - type Row = Vector3; - type Transpose = Matrix3; - - #[inline] - fn row(&self, r: usize) -> Vector3 { - Vector3::new(self[0][r], self[1][r], self[2][r]) - } - - #[inline] - fn swap_rows(&mut self, a: usize, b: usize) { - self[0].swap_elements(a, b); - self[1].swap_elements(a, b); - self[2].swap_elements(a, b); - } - - #[inline] - fn swap_columns(&mut self, a: usize, b: usize) { - unsafe { ptr::swap(&mut self[a], &mut self[b]) }; - } - - #[inline] - fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) { - let (ac, ar) = a; - let (bc, br) = b; - unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; - } - - fn transpose(&self) -> Matrix3 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - self[0][0], self[1][0], self[2][0], - self[0][1], self[1][1], self[2][1], - self[0][2], self[1][2], self[2][2], - ) - } -} - -impl SquareMatrix for Matrix3 { - type ColumnRow = Vector3; - - #[inline] - fn from_value(value: S) -> Matrix3 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - value, S::zero(), S::zero(), - S::zero(), value, S::zero(), - S::zero(), S::zero(), value, - ) - } - - #[inline] - fn from_diagonal(value: Vector3) -> Matrix3 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - value.x, S::zero(), S::zero(), - S::zero(), value.y, S::zero(), - S::zero(), S::zero(), value.z, - ) - } - - #[inline] - fn transpose_self(&mut self) { - self.swap_elements((0, 1), (1, 0)); - self.swap_elements((0, 2), (2, 0)); - self.swap_elements((1, 2), (2, 1)); - } - - fn determinant(&self) -> S { - self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2]) - - self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2]) - + self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2]) - } - - #[inline] - fn diagonal(&self) -> Vector3 { - Vector3::new(self[0][0], self[1][1], self[2][2]) - } - - fn invert(&self) -> Option> { - let det = self.determinant(); - if det == S::zero() { - None - } else { - Some( - Matrix3::from_cols( - self[1].cross(self[2]) / det, - self[2].cross(self[0]) / det, - self[0].cross(self[1]) / det, - ).transpose(), - ) - } - } - - fn is_diagonal(&self) -> bool { - ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][2], &S::zero()) - && ulps_eq!(self[1][0], &S::zero()) && ulps_eq!(self[1][2], &S::zero()) - && ulps_eq!(self[2][0], &S::zero()) && ulps_eq!(self[2][1], &S::zero()) - } - - fn is_symmetric(&self) -> bool { - ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][2], &self[2][0]) - && ulps_eq!(self[1][0], &self[0][1]) && ulps_eq!(self[1][2], &self[2][1]) - && ulps_eq!(self[2][0], &self[0][2]) && ulps_eq!(self[2][1], &self[1][2]) - } -} - -impl Matrix for Matrix4 { - type Column = Vector4; - type Row = Vector4; - type Transpose = Matrix4; - - #[inline] - fn row(&self, r: usize) -> Vector4 { - Vector4::new(self[0][r], self[1][r], self[2][r], self[3][r]) - } - - #[inline] - fn swap_rows(&mut self, a: usize, b: usize) { - self[0].swap_elements(a, b); - self[1].swap_elements(a, b); - self[2].swap_elements(a, b); - self[3].swap_elements(a, b); - } - - #[inline] - fn swap_columns(&mut self, a: usize, b: usize) { - unsafe { ptr::swap(&mut self[a], &mut self[b]) }; - } - - #[inline] - fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) { - let (ac, ar) = a; - let (bc, br) = b; - unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) }; - } - - fn transpose(&self) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - self[0][0], self[1][0], self[2][0], self[3][0], - self[0][1], self[1][1], self[2][1], self[3][1], - self[0][2], self[1][2], self[2][2], self[3][2], - self[0][3], self[1][3], self[2][3], self[3][3], - ) - } -} - -impl SquareMatrix for Matrix4 { - type ColumnRow = Vector4; - - #[inline] - fn from_value(value: S) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - value, S::zero(), S::zero(), S::zero(), - S::zero(), value, S::zero(), S::zero(), - S::zero(), S::zero(), value, S::zero(), - S::zero(), S::zero(), S::zero(), value, - ) - } - - #[inline] - fn from_diagonal(value: Vector4) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - value.x, S::zero(), S::zero(), S::zero(), - S::zero(), value.y, S::zero(), S::zero(), - S::zero(), S::zero(), value.z, S::zero(), - S::zero(), S::zero(), S::zero(), value.w, - ) - } - - fn transpose_self(&mut self) { - self.swap_elements((0, 1), (1, 0)); - self.swap_elements((0, 2), (2, 0)); - self.swap_elements((0, 3), (3, 0)); - self.swap_elements((1, 2), (2, 1)); - self.swap_elements((1, 3), (3, 1)); - self.swap_elements((2, 3), (3, 2)); - } - - fn determinant(&self) -> S { - let tmp = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) }; - tmp.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0])) - } - - #[inline] - fn diagonal(&self) -> Vector4 { - Vector4::new(self[0][0], self[1][1], self[2][2], self[3][3]) - } - - // The new implementation results in negative optimization when used - // without SIMD. so we opt them in with configuration. - // A better option would be using specialization. But currently somewhat - // specialization is too buggy, and it won't apply here. I'm getting - // weird error msgs. Help wanted. - #[cfg(not(feature = "simd"))] - fn invert(&self) -> Option> { - let det = self.determinant(); - if det == S::zero() { - None - } else { - let inv_det = S::one() / det; - let t = self.transpose(); - let cf = |i, j| { - let mat = match i { - 0 => { - Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)) - } - 1 => { - Matrix3::from_cols(t.x.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)) - } - 2 => { - Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.w.truncate_n(j)) - } - 3 => { - Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.z.truncate_n(j)) - } - _ => panic!("out of range"), - }; - let sign = if (i + j) & 1 == 1 { - -S::one() - } else { - S::one() - }; - mat.determinant() * sign * inv_det - }; - - #[cfg_attr(rustfmt, rustfmt_skip)] - Some(Matrix4::new( - cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3), - cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3), - cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3), - cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3), - )) - } - } - #[cfg(feature = "simd")] - fn invert(&self) -> Option> { - let tmp0 = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) }; - let det = tmp0.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0])); - - if det == S::zero() { - None - } else { - let inv_det = S::one() / det; - let tmp0 = tmp0 * inv_det; - let tmp1 = unsafe { det_sub_proc_unsafe(self, 0, 3, 2) * inv_det }; - let tmp2 = unsafe { det_sub_proc_unsafe(self, 0, 1, 3) * inv_det }; - let tmp3 = unsafe { det_sub_proc_unsafe(self, 0, 2, 1) * inv_det }; - Some(Matrix4::from_cols(tmp0, tmp1, tmp2, tmp3)) - } - } - - fn is_diagonal(&self) -> bool { - ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][2], &S::zero()) - && ulps_eq!(self[0][3], &S::zero()) && ulps_eq!(self[1][0], &S::zero()) - && ulps_eq!(self[1][2], &S::zero()) && ulps_eq!(self[1][3], &S::zero()) - && ulps_eq!(self[2][0], &S::zero()) && ulps_eq!(self[2][1], &S::zero()) - && ulps_eq!(self[2][3], &S::zero()) && ulps_eq!(self[3][0], &S::zero()) - && ulps_eq!(self[3][1], &S::zero()) && ulps_eq!(self[3][2], &S::zero()) - } - - fn is_symmetric(&self) -> bool { - ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][2], &self[2][0]) - && ulps_eq!(self[0][3], &self[3][0]) && ulps_eq!(self[1][0], &self[0][1]) - && ulps_eq!(self[1][2], &self[2][1]) && ulps_eq!(self[1][3], &self[3][1]) - && ulps_eq!(self[2][0], &self[0][2]) && ulps_eq!(self[2][1], &self[1][2]) - && ulps_eq!(self[2][3], &self[3][2]) && ulps_eq!(self[3][0], &self[0][3]) - && ulps_eq!(self[3][1], &self[1][3]) && ulps_eq!(self[3][2], &self[2][3]) - } -} - -impl approx::AbsDiffEq for Matrix2 { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - cast(1.0e-6f64).unwrap() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - Vector2::abs_diff_eq(&self[0], &other[0], epsilon) - && Vector2::abs_diff_eq(&self[1], &other[1], epsilon) - } -} - -impl approx::RelativeEq for Matrix2 { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - Vector2::relative_eq(&self[0], &other[0], epsilon, max_relative) - && Vector2::relative_eq(&self[1], &other[1], epsilon, max_relative) - } -} - -impl approx::UlpsEq for Matrix2 { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - Vector2::ulps_eq(&self[0], &other[0], epsilon, max_ulps) - && Vector2::ulps_eq(&self[1], &other[1], epsilon, max_ulps) - } -} - -impl approx::AbsDiffEq for Matrix3 { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - cast(1.0e-6f64).unwrap() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - Vector3::abs_diff_eq(&self[0], &other[0], epsilon) - && Vector3::abs_diff_eq(&self[1], &other[1], epsilon) - && Vector3::abs_diff_eq(&self[2], &other[2], epsilon) - } -} - -impl approx::RelativeEq for Matrix3 { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - Vector3::relative_eq(&self[0], &other[0], epsilon, max_relative) - && Vector3::relative_eq(&self[1], &other[1], epsilon, max_relative) - && Vector3::relative_eq(&self[2], &other[2], epsilon, max_relative) - } -} - -impl approx::UlpsEq for Matrix3 { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - Vector3::ulps_eq(&self[0], &other[0], epsilon, max_ulps) - && Vector3::ulps_eq(&self[1], &other[1], epsilon, max_ulps) - && Vector3::ulps_eq(&self[2], &other[2], epsilon, max_ulps) - } -} - -impl approx::AbsDiffEq for Matrix4 { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - cast(1.0e-6f64).unwrap() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - Vector4::abs_diff_eq(&self[0], &other[0], epsilon) - && Vector4::abs_diff_eq(&self[1], &other[1], epsilon) - && Vector4::abs_diff_eq(&self[2], &other[2], epsilon) - && Vector4::abs_diff_eq(&self[3], &other[3], epsilon) - } -} - -impl approx::RelativeEq for Matrix4 { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - Vector4::relative_eq(&self[0], &other[0], epsilon, max_relative) - && Vector4::relative_eq(&self[1], &other[1], epsilon, max_relative) - && Vector4::relative_eq(&self[2], &other[2], epsilon, max_relative) - && Vector4::relative_eq(&self[3], &other[3], epsilon, max_relative) - } -} - -impl approx::UlpsEq for Matrix4 { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - Vector4::ulps_eq(&self[0], &other[0], epsilon, max_ulps) - && Vector4::ulps_eq(&self[1], &other[1], epsilon, max_ulps) - && Vector4::ulps_eq(&self[2], &other[2], epsilon, max_ulps) - && Vector4::ulps_eq(&self[3], &other[3], epsilon, max_ulps) - } -} - -impl Transform> for Matrix3 { - fn one() -> Matrix3 { - One::one() - } - - fn look_at(eye: Point2, center: Point2, up: Vector2) -> Matrix3 { - let dir = center - eye; - Matrix3::from(Matrix2::look_at(dir, up)) - } - - fn transform_vector(&self, vec: Vector2) -> Vector2 { - (self * vec.extend(S::zero())).truncate() - } - - fn transform_point(&self, point: Point2) -> Point2 { - Point2::from_vec((self * Point3::new(point.x, point.y, S::one()).to_vec()).truncate()) - } - - fn concat(&self, other: &Matrix3) -> Matrix3 { - self * other - } - - fn inverse_transform(&self) -> Option> { - SquareMatrix::invert(self) - } -} - -impl Transform> for Matrix3 { - fn one() -> Matrix3 { - One::one() - } - - fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix3 { - let dir = center - eye; - Matrix3::look_at(dir, up) - } - - fn transform_vector(&self, vec: Vector3) -> Vector3 { - self * vec - } - - fn transform_point(&self, point: Point3) -> Point3 { - Point3::from_vec(self * point.to_vec()) - } - - fn concat(&self, other: &Matrix3) -> Matrix3 { - self * other - } - - fn inverse_transform(&self) -> Option> { - SquareMatrix::invert(self) - } -} - -impl Transform> for Matrix4 { - fn one() -> Matrix4 { - One::one() - } - - fn look_at(eye: Point3, center: Point3, up: Vector3) -> Matrix4 { - Matrix4::look_at(eye, center, up) - } - - fn transform_vector(&self, vec: Vector3) -> Vector3 { - (self * vec.extend(S::zero())).truncate() - } - - fn transform_point(&self, point: Point3) -> Point3 { - Point3::from_homogeneous(self * point.to_homogeneous()) - } - - fn concat(&self, other: &Matrix4) -> Matrix4 { - self * other - } - - fn inverse_transform(&self) -> Option> { - SquareMatrix::invert(self) - } -} - -impl Transform2 for Matrix3 {} - -impl Transform3 for Matrix3 {} - -impl Transform3 for Matrix4 {} - -macro_rules! impl_matrix { - ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => { - impl_operator!( Neg for $MatrixN { - fn neg(matrix) -> $MatrixN { $MatrixN { $($field: -matrix.$field),+ } } - }); - - impl_operator!( Mul for $MatrixN { - fn mul(matrix, scalar) -> $MatrixN { $MatrixN { $($field: matrix.$field * scalar),+ } } - }); - impl_operator!( Div for $MatrixN { - fn div(matrix, scalar) -> $MatrixN { $MatrixN { $($field: matrix.$field / scalar),+ } } - }); - impl_operator!( Rem for $MatrixN { - fn rem(matrix, scalar) -> $MatrixN { $MatrixN { $($field: matrix.$field % scalar),+ } } - }); - impl_assignment_operator!( MulAssign for $MatrixN { - fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } - }); - impl_assignment_operator!( DivAssign for $MatrixN { - fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } - }); - impl_assignment_operator!( RemAssign for $MatrixN { - fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } - }); - - impl_operator!( Add<$MatrixN > for $MatrixN { - fn add(lhs, rhs) -> $MatrixN { $MatrixN { $($field: lhs.$field + rhs.$field),+ } } - }); - impl_operator!( Sub<$MatrixN > for $MatrixN { - fn sub(lhs, rhs) -> $MatrixN { $MatrixN { $($field: lhs.$field - rhs.$field),+ } } - }); - impl> AddAssign<$MatrixN> for $MatrixN { - fn add_assign(&mut self, other: $MatrixN) { $(self.$field += other.$field);+ } - } - impl> SubAssign<$MatrixN> for $MatrixN { - fn sub_assign(&mut self, other: $MatrixN) { $(self.$field -= other.$field);+ } - } - - impl iter::Sum<$MatrixN> for $MatrixN { - #[inline] - fn sum>>(iter: I) -> $MatrixN { - iter.fold($MatrixN::zero(), Add::add) - } - } - - impl<'a, S: 'a + BaseFloat> iter::Sum<&'a $MatrixN> for $MatrixN { - #[inline] - fn sum>>(iter: I) -> $MatrixN { - iter.fold($MatrixN::zero(), Add::add) - } - } - - impl iter::Product for $MatrixN { - #[inline] - fn product>>(iter: I) -> $MatrixN { - iter.fold($MatrixN::identity(), Mul::mul) - } - } - - impl<'a, S: 'a + BaseFloat> iter::Product<&'a $MatrixN> for $MatrixN { - #[inline] - fn product>>(iter: I) -> $MatrixN { - iter.fold($MatrixN::identity(), Mul::mul) - } - } - - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - impl_scalar_ops!($MatrixN { $($field),+ }); - - - impl $MatrixN { - /// Component-wise casting to another type - #[inline] - pub fn cast(&self) -> Option<$MatrixN> { - $( - let $field = match self.$field.cast() { - Some(field) => field, - None => return None - }; - )+ - Some($MatrixN { $($field),+ }) - } - } - } -} - -macro_rules! impl_scalar_ops { - ($MatrixN:ident<$S:ident> { $($field:ident),+ }) => { - impl_operator!(Mul<$MatrixN<$S>> for $S { - fn mul(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar * matrix.$field),+ } } - }); - impl_operator!(Div<$MatrixN<$S>> for $S { - fn div(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar / matrix.$field),+ } } - }); - impl_operator!(Rem<$MatrixN<$S>> for $S { - fn rem(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar % matrix.$field),+ } } - }); - }; -} - -impl_matrix!(Matrix2, Vector2 { x: 0, y: 1 }); -impl_matrix!(Matrix3, Vector3 { x: 0, y: 1, z: 2 }); -#[cfg_attr(rustfmt, rustfmt_skip)] -impl_matrix!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 }); - -macro_rules! impl_mv_operator { - ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => { - impl_operator!( Mul<$VectorN > for $MatrixN { - fn mul(matrix, vector) -> $VectorN {$VectorN::new($(matrix.row($row_index).dot(vector.clone())),+)} - }); - } -} - -impl_mv_operator!(Matrix2, Vector2 { x: 0, y: 1 }); -impl_mv_operator!(Matrix3, Vector3 { x: 0, y: 1, z: 2 }); -#[cfg(not(feature = "simd"))] -#[cfg_attr(rustfmt, rustfmt_skip)] -impl_mv_operator!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 }); - -#[cfg(feature = "simd")] -impl_operator!( Mul > for Matrix4 { - fn mul(matrix, vector) -> Vector4 { - matrix[0] * vector[0] + matrix[1] * vector[1] + matrix[2] * vector[2] + matrix[3] * vector[3] - } -}); - -impl_operator!( Mul > for Matrix2 { - fn mul(lhs, rhs) -> Matrix2 { - Matrix2::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]), - lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1])) - } -}); - -impl_operator!( Mul > for Matrix3 { - fn mul(lhs, rhs) -> Matrix3 { - Matrix3::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]), lhs.row(2).dot(rhs[0]), - lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1]), lhs.row(2).dot(rhs[1]), - lhs.row(0).dot(rhs[2]), lhs.row(1).dot(rhs[2]), lhs.row(2).dot(rhs[2])) - } -}); - -// Using self.row(0).dot(other[0]) like the other matrix multiplies -// causes the LLVM to miss identical loads and multiplies. This optimization -// causes the code to be auto vectorized properly increasing the performance -// around ~4 times. -// Update: this should now be a bit more efficient - -impl_operator!( Mul > for Matrix4 { - fn mul(lhs, rhs) -> Matrix4 { - { - let a = lhs[0]; - let b = lhs[1]; - let c = lhs[2]; - let d = lhs[3]; - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::from_cols( - a*rhs[0][0] + b*rhs[0][1] + c*rhs[0][2] + d*rhs[0][3], - a*rhs[1][0] + b*rhs[1][1] + c*rhs[1][2] + d*rhs[1][3], - a*rhs[2][0] + b*rhs[2][1] + c*rhs[2][2] + d*rhs[2][3], - a*rhs[3][0] + b*rhs[3][1] + c*rhs[3][2] + d*rhs[3][3], - ) - } - } -}); - -macro_rules! index_operators { - ($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { - impl<$S> Index<$I> for $MatrixN<$S> { - type Output = $Output; - - #[inline] - fn index<'a>(&'a self, i: $I) -> &'a $Output { - let v: &[[$S; $n]; $n] = self.as_ref(); - From::from(&v[i]) - } - } - - impl<$S> IndexMut<$I> for $MatrixN<$S> { - #[inline] - fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { - let v: &mut [[$S; $n]; $n] = self.as_mut(); - From::from(&mut v[i]) - } - } - } -} - -index_operators!(Matrix2, 2, Vector2, usize); -index_operators!(Matrix3, 3, Vector3, usize); -index_operators!(Matrix4, 4, Vector4, usize); -// index_operators!(Matrix2, 2, [Vector2], Range); -// index_operators!(Matrix3, 3, [Vector3], Range); -// index_operators!(Matrix4, 4, [Vector4], Range); -// index_operators!(Matrix2, 2, [Vector2], RangeTo); -// index_operators!(Matrix3, 3, [Vector3], RangeTo); -// index_operators!(Matrix4, 4, [Vector4], RangeTo); -// index_operators!(Matrix2, 2, [Vector2], RangeFrom); -// index_operators!(Matrix3, 3, [Vector3], RangeFrom); -// index_operators!(Matrix4, 4, [Vector4], RangeFrom); -// index_operators!(Matrix2, 2, [Vector2], RangeFull); -// index_operators!(Matrix3, 3, [Vector3], RangeFull); -// index_operators!(Matrix4, 4, [Vector4], RangeFull); - -impl From> for Matrix3 -where - A: Angle + Into::Unitless>>, -{ - fn from(src: Euler) -> Matrix3 { - // Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf - let (sx, cx) = Rad::sin_cos(src.x.into()); - let (sy, cy) = Rad::sin_cos(src.y.into()); - let (sz, cz) = Rad::sin_cos(src.z.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, - -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, - sy, -sx * cy, cx * cy, - ) - } -} - -impl From> for Matrix4 -where - A: Angle + Into::Unitless>>, -{ - fn from(src: Euler) -> Matrix4 { - // Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf - let (sx, cx) = Rad::sin_cos(src.x.into()); - let (sy, cy) = Rad::sin_cos(src.y.into()); - let (sz, cz) = Rad::sin_cos(src.z.into()); - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, A::Unitless::zero(), - -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, A::Unitless::zero(), - sy, -sx * cy, cx * cy, A::Unitless::zero(), - A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one(), - ) - } -} - -macro_rules! fixed_array_conversions { - ($MatrixN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { - impl<$S> Into<[[$S; $n]; $n]> for $MatrixN<$S> { - #[inline] - fn into(self) -> [[$S; $n]; $n] { - match self { $MatrixN { $($field),+ } => [$($field.into()),+] } - } - } - - impl<$S> AsRef<[[$S; $n]; $n]> for $MatrixN<$S> { - #[inline] - fn as_ref(&self) -> &[[$S; $n]; $n] { - unsafe { mem::transmute(self) } - } - } - - impl<$S> AsMut<[[$S; $n]; $n]> for $MatrixN<$S> { - #[inline] - fn as_mut(&mut self) -> &mut [[$S; $n]; $n] { - unsafe { mem::transmute(self) } - } - } - - impl<$S: Copy> From<[[$S; $n]; $n]> for $MatrixN<$S> { - #[inline] - fn from(m: [[$S; $n]; $n]) -> $MatrixN<$S> { - // We need to use a copy here because we can't pattern match on arrays yet - $MatrixN { $($field: From::from(m[$index])),+ } - } - } - - impl<'a, $S> From<&'a [[$S; $n]; $n]> for &'a $MatrixN<$S> { - #[inline] - fn from(m: &'a [[$S; $n]; $n]) -> &'a $MatrixN<$S> { - unsafe { mem::transmute(m) } - } - } - - impl<'a, $S> From<&'a mut [[$S; $n]; $n]> for &'a mut $MatrixN<$S> { - #[inline] - fn from(m: &'a mut [[$S; $n]; $n]) -> &'a mut $MatrixN<$S> { - unsafe { mem::transmute(m) } - } - } - - // impl<$S> Into<[$S; ($n * $n)]> for $MatrixN<$S> { - // #[inline] - // fn into(self) -> [[$S; $n]; $n] { - // // TODO: Not sure how to implement this... - // unimplemented!() - // } - // } - - impl<$S> AsRef<[$S; ($n * $n)]> for $MatrixN<$S> { - #[inline] - fn as_ref(&self) -> &[$S; ($n * $n)] { - unsafe { mem::transmute(self) } - } - } - - impl<$S> AsMut<[$S; ($n * $n)]> for $MatrixN<$S> { - #[inline] - fn as_mut(&mut self) -> &mut [$S; ($n * $n)] { - unsafe { mem::transmute(self) } - } - } - - // impl<$S> From<[$S; ($n * $n)]> for $MatrixN<$S> { - // #[inline] - // fn from(m: [$S; ($n * $n)]) -> $MatrixN<$S> { - // // TODO: Not sure how to implement this... - // unimplemented!() - // } - // } - - impl<'a, $S> From<&'a [$S; ($n * $n)]> for &'a $MatrixN<$S> { - #[inline] - fn from(m: &'a [$S; ($n * $n)]) -> &'a $MatrixN<$S> { - unsafe { mem::transmute(m) } - } - } - - impl<'a, $S> From<&'a mut [$S; ($n * $n)]> for &'a mut $MatrixN<$S> { - #[inline] - fn from(m: &'a mut [$S; ($n * $n)]) -> &'a mut $MatrixN<$S> { - unsafe { mem::transmute(m) } - } - } - } -} - -fixed_array_conversions!(Matrix2 { x:0, y:1 }, 2); -fixed_array_conversions!(Matrix3 { x:0, y:1, z:2 }, 3); -fixed_array_conversions!(Matrix4 { x:0, y:1, z:2, w:3 }, 4); - -#[cfg(feature = "mint")] -macro_rules! mint_conversions { - ($MatrixN:ident { $($field:ident),+ }, $MintN:ident) => { - impl Into> for $MatrixN { - #[inline] - fn into(self) -> mint::$MintN { - mint::$MintN { $($field: self.$field.into()),+ } - } - } - - impl From> for $MatrixN { - #[inline] - fn from(m: mint::$MintN) -> Self { - $MatrixN { $($field: m.$field.into()),+ } - } - } - - } -} - -#[cfg(feature = "mint")] -mint_conversions!(Matrix2 { x, y }, ColumnMatrix2); -#[cfg(feature = "mint")] -mint_conversions!(Matrix3 { x, y, z }, ColumnMatrix3); -#[cfg(feature = "mint")] -mint_conversions!(Matrix4 { x, y, z, w }, ColumnMatrix4); - -impl From> for Matrix3 { - /// Clone the elements of a 2-dimensional matrix into the top-left corner - /// of a 3-dimensional identity matrix. - fn from(m: Matrix2) -> Matrix3 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - m[0][0], m[0][1], S::zero(), - m[1][0], m[1][1], S::zero(), - S::zero(), S::zero(), S::one(), - ) - } -} - -impl From> for Matrix4 { - /// Clone the elements of a 2-dimensional matrix into the top-left corner - /// of a 4-dimensional identity matrix. - fn from(m: Matrix2) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - m[0][0], m[0][1], S::zero(), S::zero(), - m[1][0], m[1][1], S::zero(), S::zero(), - S::zero(), S::zero(), S::one(), S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } -} - -impl From> for Matrix4 { - /// Clone the elements of a 3-dimensional matrix into the top-left corner - /// of a 4-dimensional identity matrix. - fn from(m: Matrix3) -> Matrix4 { - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - m[0][0], m[0][1], m[0][2], S::zero(), - m[1][0], m[1][1], m[1][2], S::zero(), - m[2][0], m[2][1], m[2][2], S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } -} - -impl From> for Quaternion { - /// Convert the matrix to a quaternion - fn from(mat: Matrix3) -> Quaternion { - // http://www.cs.ucr.edu/~vbz/resources/quatut.pdf - let trace = mat.trace(); - let half: S = cast(0.5f64).unwrap(); - - if trace >= S::zero() { - let s = (S::one() + trace).sqrt(); - let w = half * s; - let s = half / s; - let x = (mat[1][2] - mat[2][1]) * s; - let y = (mat[2][0] - mat[0][2]) * s; - let z = (mat[0][1] - mat[1][0]) * s; - Quaternion::new(w, x, y, z) - } else if (mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2]) { - let s = ((mat[0][0] - mat[1][1] - mat[2][2]) + S::one()).sqrt(); - let x = half * s; - let s = half / s; - let y = (mat[1][0] + mat[0][1]) * s; - let z = (mat[0][2] + mat[2][0]) * s; - let w = (mat[1][2] - mat[2][1]) * s; - Quaternion::new(w, x, y, z) - } else if mat[1][1] > mat[2][2] { - let s = ((mat[1][1] - mat[0][0] - mat[2][2]) + S::one()).sqrt(); - let y = half * s; - let s = half / s; - let z = (mat[2][1] + mat[1][2]) * s; - let x = (mat[1][0] + mat[0][1]) * s; - let w = (mat[2][0] - mat[0][2]) * s; - Quaternion::new(w, x, y, z) - } else { - let s = ((mat[2][2] - mat[0][0] - mat[1][1]) + S::one()).sqrt(); - let z = half * s; - let s = half / s; - let x = (mat[0][2] + mat[2][0]) * s; - let y = (mat[2][1] + mat[1][2]) * s; - let w = (mat[0][1] - mat[1][0]) * s; - Quaternion::new(w, x, y, z) - } - } -} - -impl fmt::Debug for Matrix2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Matrix2 ")); - <[[S; 2]; 2] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Matrix3 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Matrix3 ")); - <[[S; 3]; 3] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Matrix4 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Matrix4 ")); - <[[S; 4]; 4] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl Distribution> for Standard - where - Standard: Distribution>, - S: BaseFloat { - #[inline] - fn sample(&self, rng: &mut R) -> Matrix2 { - Matrix2 { - x: self.sample(rng), - y: self.sample(rng), - } - } -} - -impl Distribution> for Standard - where Standard: Distribution>, - S: BaseFloat { - #[inline] - fn sample(&self, rng: &mut R) -> Matrix3 { - Matrix3 { - x: rng.gen(), - y: rng.gen(), - z: rng.gen(), - } - } -} - -impl Distribution> for Standard - where Standard: Distribution>, - S: BaseFloat { - #[inline] - fn sample(&self, rng: &mut R) -> Matrix4 { - Matrix4 { - x: rng.gen(), - y: rng.gen(), - z: rng.gen(), - w: rng.gen(), - } - } -} - -// Sub procedure for SIMD when dealing with determinant and inversion -#[inline] -unsafe fn det_sub_proc_unsafe( - m: &Matrix4, - x: usize, - y: usize, - z: usize, -) -> Vector4 { - let s: &[S; 16] = m.as_ref(); - let a = Vector4::new( - *s.get_unchecked(4 + x), - *s.get_unchecked(12 + x), - *s.get_unchecked(x), - *s.get_unchecked(8 + x), - ); - let b = Vector4::new( - *s.get_unchecked(8 + y), - *s.get_unchecked(8 + y), - *s.get_unchecked(4 + y), - *s.get_unchecked(4 + y), - ); - let c = Vector4::new( - *s.get_unchecked(12 + z), - *s.get_unchecked(z), - *s.get_unchecked(12 + z), - *s.get_unchecked(z), - ); - - let d = Vector4::new( - *s.get_unchecked(8 + x), - *s.get_unchecked(8 + x), - *s.get_unchecked(4 + x), - *s.get_unchecked(4 + x), - ); - let e = Vector4::new( - *s.get_unchecked(12 + y), - *s.get_unchecked(y), - *s.get_unchecked(12 + y), - *s.get_unchecked(y), - ); - let f = Vector4::new( - *s.get_unchecked(4 + z), - *s.get_unchecked(12 + z), - *s.get_unchecked(z), - *s.get_unchecked(8 + z), - ); - - let g = Vector4::new( - *s.get_unchecked(12 + x), - *s.get_unchecked(x), - *s.get_unchecked(12 + x), - *s.get_unchecked(x), - ); - let h = Vector4::new( - *s.get_unchecked(4 + y), - *s.get_unchecked(12 + y), - *s.get_unchecked(y), - *s.get_unchecked(8 + y), - ); - let i = Vector4::new( - *s.get_unchecked(8 + z), - *s.get_unchecked(8 + z), - *s.get_unchecked(4 + z), - *s.get_unchecked(4 + z), - ); - let mut tmp = a.mul_element_wise(b.mul_element_wise(c)); - tmp += d.mul_element_wise(e.mul_element_wise(f)); - tmp += g.mul_element_wise(h.mul_element_wise(i)); - tmp -= a.mul_element_wise(e.mul_element_wise(i)); - tmp -= d.mul_element_wise(h.mul_element_wise(c)); - tmp -= g.mul_element_wise(b.mul_element_wise(f)); - tmp -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/point.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/point.rs deleted file mode 100755 index a50c92f..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/point.rs +++ /dev/null @@ -1,586 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Points are fixed positions in affine space with no length or direction. This -//! distinguishes them from vectors, which have a length and direction, but do -//! not have a fixed position. - -use num_traits::{Bounded, NumCast}; -use std::fmt; -use std::mem; -use std::ops::*; - -use structure::*; - -use approx; -use num::{BaseFloat, BaseNum}; -use vector::{Vector1, Vector2, Vector3, Vector4}; - -#[cfg(feature = "mint")] -use mint; - -/// A point in 1-dimensional space. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Point1 { - pub x: S, -} - -/// A point in 2-dimensional space. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Point2 { - pub x: S, - pub y: S, -} - -/// A point in 3-dimensional space. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(PartialEq, Eq, Copy, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Point3 { - pub x: S, - pub y: S, - pub z: S, -} - -impl Point3 { - #[inline] - pub fn from_homogeneous(v: Vector4) -> Point3 { - let e = v.truncate() * (S::one() / v.w); - Point3::new(e.x, e.y, e.z) //FIXME - } - - #[inline] - pub fn to_homogeneous(self) -> Vector4 { - Vector4::new(self.x, self.y, self.z, S::one()) - } -} - -macro_rules! impl_point { - ($PointN:ident { $($field:ident),+ }, $VectorN:ident, $n:expr) => { - impl $PointN { - /// Construct a new point, using the provided values. - #[inline] - pub const fn new($($field: S),+) -> $PointN { - $PointN { $($field: $field),+ } - } - - /// Perform the given operation on each field in the point, returning a new point - /// constructed from the operations. - #[inline] - pub fn map(self, mut f: F) -> $PointN - where F: FnMut(S) -> U - { - $PointN { $($field: f(self.$field)),+ } - } - } - - impl Array for $PointN { - type Element = S; - - #[inline] - fn len() -> usize { - $n - } - - #[inline] - fn from_value(scalar: S) -> $PointN { - $PointN { $($field: scalar),+ } - } - - #[inline] - fn sum(self) -> S where S: Add { - fold_array!(add, { $(self.$field),+ }) - } - - #[inline] - fn product(self) -> S where S: Mul { - fold_array!(mul, { $(self.$field),+ }) - } - - fn is_finite(&self) -> bool where S: BaseFloat { - $(self.$field.is_finite())&&+ - } - } - - impl $PointN { - /// Component-wise casting to another type - #[inline] - pub fn cast(&self) -> Option<$PointN> { - $( - let $field = match NumCast::from(self.$field) { - Some(field) => field, - None => return None - }; - )+ - Some($PointN { $($field),+ }) - } - } - - impl MetricSpace for $PointN { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } - } - - impl EuclideanSpace for $PointN { - type Scalar = S; - type Diff = $VectorN; - - #[inline] - fn origin() -> $PointN { - $PointN { $($field: S::zero()),+ } - } - - #[inline] - fn from_vec(v: $VectorN) -> $PointN { - $PointN::new($(v.$field),+) - } - - #[inline] - fn to_vec(self) -> $VectorN { - $VectorN::new($(self.$field),+) - } - - #[inline] - fn dot(self, v: $VectorN) -> S { - $VectorN::new($(self.$field * v.$field),+).sum() - } - } - - impl approx::AbsDiffEq for $PointN { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) - -> bool - { - $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ - } - } - - impl approx::RelativeEq for $PointN { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ - } - } - - impl approx::UlpsEq for $PointN { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ - } - } - - impl Bounded for $PointN { - #[inline] - fn min_value() -> $PointN { - $PointN { $($field: S::min_value()),+ } - } - - #[inline] - fn max_value() -> $PointN { - $PointN { $($field: S::max_value()),+ } - } - } - - impl_operator!( Add<$VectorN > for $PointN { - fn add(lhs, rhs) -> $PointN { $PointN::new($(lhs.$field + rhs.$field),+) } - }); - impl_operator!( Sub<$VectorN> for $PointN { - fn sub(lhs, rhs) -> $PointN { $PointN::new($(lhs.$field - rhs.$field),+) } - }); - impl_assignment_operator!( AddAssign<$VectorN > for $PointN { - fn add_assign(&mut self, vector) { $(self.$field += vector.$field);+ } - }); - impl_assignment_operator!( SubAssign<$VectorN> for $PointN { - fn sub_assign(&mut self, vector) { $(self.$field -= vector.$field);+ } - }); - - impl_operator!( Sub<$PointN > for $PointN { - fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } - }); - - impl_operator!( Mul for $PointN { - fn mul(point, scalar) -> $PointN { $PointN::new($(point.$field * scalar),+) } - }); - impl_operator!( Div for $PointN { - fn div(point, scalar) -> $PointN { $PointN::new($(point.$field / scalar),+) } - }); - impl_operator!( Rem for $PointN { - fn rem(point, scalar) -> $PointN { $PointN::new($(point.$field % scalar),+) } - }); - impl_assignment_operator!( MulAssign for $PointN { - fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } - }); - impl_assignment_operator!( DivAssign for $PointN { - fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } - }); - impl_assignment_operator!( RemAssign for $PointN { - fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } - }); - - impl ElementWise for $PointN { - #[inline] fn add_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field + rhs.$field),+) } - #[inline] fn sub_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field - rhs.$field),+) } - #[inline] fn mul_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field * rhs.$field),+) } - #[inline] fn div_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field / rhs.$field),+) } - #[inline] fn rem_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field % rhs.$field),+) } - - #[inline] fn add_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field += rhs.$field);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field -= rhs.$field);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field *= rhs.$field);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field /= rhs.$field);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field %= rhs.$field);+ } - } - - impl ElementWise for $PointN { - #[inline] fn add_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field + rhs),+) } - #[inline] fn sub_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field - rhs),+) } - #[inline] fn mul_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field * rhs),+) } - #[inline] fn div_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field / rhs),+) } - #[inline] fn rem_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field % rhs),+) } - - #[inline] fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } - #[inline] fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } - #[inline] fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } - #[inline] fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } - #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } - } - - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - impl_scalar_ops!($PointN { $($field),+ }); - - impl_index_operators!($PointN, $n, S, usize); - impl_index_operators!($PointN, $n, [S], Range); - impl_index_operators!($PointN, $n, [S], RangeTo); - impl_index_operators!($PointN, $n, [S], RangeFrom); - impl_index_operators!($PointN, $n, [S], RangeFull); - } -} - -macro_rules! impl_scalar_ops { - ($PointN:ident<$S:ident> { $($field:ident),+ }) => { - impl_operator!(Mul<$PointN<$S>> for $S { - fn mul(scalar, point) -> $PointN<$S> { $PointN::new($(scalar * point.$field),+) } - }); - impl_operator!(Div<$PointN<$S>> for $S { - fn div(scalar, point) -> $PointN<$S> { $PointN::new($(scalar / point.$field),+) } - }); - impl_operator!(Rem<$PointN<$S>> for $S { - fn rem(scalar, point) -> $PointN<$S> { $PointN::new($(scalar % point.$field),+) } - }); - }; -} - -impl_point!(Point1 { x }, Vector1, 1); -impl_point!(Point2 { x, y }, Vector2, 2); -impl_point!(Point3 { x, y, z }, Vector3, 3); - -impl Point1 { - impl_swizzle_functions!(Point1, Point2, Point3, S, x); -} - -impl Point2 { - impl_swizzle_functions!(Point1, Point2, Point3, S, xy); -} - -impl Point3 { - impl_swizzle_functions!(Point1, Point2, Point3, S, xyz); -} - -impl_fixed_array_conversions!(Point1 { x: 0 }, 1); -impl_fixed_array_conversions!(Point2 { x: 0, y: 1 }, 2); -impl_fixed_array_conversions!(Point3 { x: 0, y: 1, z: 2 }, 3); - -impl_tuple_conversions!(Point1 { x }, (S,)); -impl_tuple_conversions!(Point2 { x, y }, (S, S)); -impl_tuple_conversions!(Point3 { x, y, z }, (S, S, S)); - -#[cfg(feature = "mint")] -impl_mint_conversions!(Point2 { x, y }, Point2); -#[cfg(feature = "mint")] -impl_mint_conversions!(Point3 { x, y, z }, Point3); - -impl fmt::Debug for Point1 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Point1 ")); - <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Point2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Point2 ")); - <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -impl fmt::Debug for Point3 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Point3 ")); - <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) - } -} - -#[cfg(test)] -mod tests { - mod point2 { - use point::*; - - const POINT2: Point2 = Point2 { x: 1, y: 2 }; - - #[test] - fn test_index() { - assert_eq!(POINT2[0], POINT2.x); - assert_eq!(POINT2[1], POINT2.y); - } - - #[test] - fn test_index_mut() { - let mut p = POINT2; - *&mut p[0] = 0; - assert_eq!(p, [0, 2].into()); - } - - #[test] - #[should_panic] - fn test_index_out_of_bounds() { - POINT2[2]; - } - - #[test] - fn test_index_range() { - assert_eq!(&POINT2[..0], &[]); - assert_eq!(&POINT2[..1], &[1]); - assert_eq!(POINT2[..0].len(), 0); - assert_eq!(POINT2[..1].len(), 1); - assert_eq!(&POINT2[2..], &[]); - assert_eq!(&POINT2[1..], &[2]); - assert_eq!(POINT2[2..].len(), 0); - assert_eq!(POINT2[1..].len(), 1); - assert_eq!(&POINT2[..], &[1, 2]); - assert_eq!(POINT2[..].len(), 2); - } - - #[test] - fn test_into() { - let p = POINT2; - { - let p: [i32; 2] = p.into(); - assert_eq!(p, [1, 2]); - } - { - let p: (i32, i32) = p.into(); - assert_eq!(p, (1, 2)); - } - } - - #[test] - fn test_as_ref() { - let p = POINT2; - { - let p: &[i32; 2] = p.as_ref(); - assert_eq!(p, &[1, 2]); - } - { - let p: &(i32, i32) = p.as_ref(); - assert_eq!(p, &(1, 2)); - } - } - - #[test] - fn test_as_mut() { - let mut p = POINT2; - { - let p: &mut [i32; 2] = p.as_mut(); - assert_eq!(p, &mut [1, 2]); - } - { - let p: &mut (i32, i32) = p.as_mut(); - assert_eq!(p, &mut (1, 2)); - } - } - - #[test] - fn test_from() { - assert_eq!(Point2::from([1, 2]), POINT2); - { - let p = &[1, 2]; - let p: &Point2<_> = From::from(p); - assert_eq!(p, &POINT2); - } - { - let p = &mut [1, 2]; - let p: &mut Point2<_> = From::from(p); - assert_eq!(p, &POINT2); - } - assert_eq!(Point2::from((1, 2)), POINT2); - { - let p = &(1, 2); - let p: &Point2<_> = From::from(p); - assert_eq!(p, &POINT2); - } - { - let p = &mut (1, 2); - let p: &mut Point2<_> = From::from(p); - assert_eq!(p, &POINT2); - } - } - } - - mod point3 { - use point::*; - - const POINT3: Point3 = Point3 { x: 1, y: 2, z: 3 }; - - #[test] - fn test_index() { - assert_eq!(POINT3[0], POINT3.x); - assert_eq!(POINT3[1], POINT3.y); - assert_eq!(POINT3[2], POINT3.z); - } - - #[test] - fn test_index_mut() { - let mut p = POINT3; - *&mut p[1] = 0; - assert_eq!(p, [1, 0, 3].into()); - } - - #[test] - #[should_panic] - fn test_index_out_of_bounds() { - POINT3[3]; - } - - #[test] - fn test_index_range() { - assert_eq!(&POINT3[..1], &[1]); - assert_eq!(&POINT3[..2], &[1, 2]); - assert_eq!(POINT3[..1].len(), 1); - assert_eq!(POINT3[..2].len(), 2); - assert_eq!(&POINT3[2..], &[3]); - assert_eq!(&POINT3[1..], &[2, 3]); - assert_eq!(POINT3[2..].len(), 1); - assert_eq!(POINT3[1..].len(), 2); - assert_eq!(&POINT3[..], &[1, 2, 3]); - assert_eq!(POINT3[..].len(), 3); - } - - #[test] - fn test_into() { - let p = POINT3; - { - let p: [i32; 3] = p.into(); - assert_eq!(p, [1, 2, 3]); - } - { - let p: (i32, i32, i32) = p.into(); - assert_eq!(p, (1, 2, 3)); - } - } - - #[test] - fn test_as_ref() { - let p = POINT3; - { - let p: &[i32; 3] = p.as_ref(); - assert_eq!(p, &[1, 2, 3]); - } - { - let p: &(i32, i32, i32) = p.as_ref(); - assert_eq!(p, &(1, 2, 3)); - } - } - - #[test] - fn test_as_mut() { - let mut p = POINT3; - { - let p: &mut [i32; 3] = p.as_mut(); - assert_eq!(p, &mut [1, 2, 3]); - } - { - let p: &mut (i32, i32, i32) = p.as_mut(); - assert_eq!(p, &mut (1, 2, 3)); - } - } - - #[test] - fn test_from() { - assert_eq!(Point3::from([1, 2, 3]), POINT3); - { - let p = &[1, 2, 3]; - let p: &Point3<_> = From::from(p); - assert_eq!(p, &POINT3); - } - { - let p = &mut [1, 2, 3]; - let p: &mut Point3<_> = From::from(p); - assert_eq!(p, &POINT3); - } - assert_eq!(Point3::from((1, 2, 3)), POINT3); - { - let p = &(1, 2, 3); - let p: &Point3<_> = From::from(p); - assert_eq!(p, &POINT3); - } - { - let p = &mut (1, 2, 3); - let p: &mut Point3<_> = From::from(p); - assert_eq!(p, &POINT3); - } - } - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/quaternion.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/quaternion.rs deleted file mode 100755 index ff4ba4d..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/quaternion.rs +++ /dev/null @@ -1,978 +0,0 @@ -// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::iter; -use std::mem; -use std::ops::*; - -use rand::distributions::{Distribution, Standard}; -use rand::Rng; -use num_traits::{cast, NumCast}; - -use structure::*; - -use angle::Rad; -use approx; -use euler::Euler; -use matrix::{Matrix3, Matrix4}; -use num::BaseFloat; -use point::Point3; -use rotation::{Basis3, Rotation, Rotation3}; -use vector::Vector3; - -#[cfg(feature = "simd")] -use simd::f32x4 as Simdf32x4; - -#[cfg(feature = "mint")] -use mint; - -/// A [quaternion](https://en.wikipedia.org/wiki/Quaternion) in scalar/vector -/// form. -/// -/// This type is marked as `#[repr(C)]`. -#[repr(C)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Quaternion { - /// The scalar part of the quaternion. - pub s: S, - /// The vector part of the quaternion. - pub v: Vector3, -} - -#[cfg(feature = "simd")] -impl From for Quaternion { - #[inline] - fn from(f: Simdf32x4) -> Self { - unsafe { - let mut ret: Self = mem::uninitialized(); - { - let ret_mut: &mut [f32; 4] = ret.as_mut(); - f.store(ret_mut.as_mut(), 0 as usize); - } - ret - } - } -} - -#[cfg(feature = "simd")] -impl Into for Quaternion { - #[inline] - fn into(self) -> Simdf32x4 { - let self_ref: &[f32; 4] = self.as_ref(); - Simdf32x4::load(self_ref.as_ref(), 0 as usize) - } -} - -impl Quaternion { - /// Construct a new quaternion from one scalar component and three - /// imaginary components. - #[inline] - pub const fn new(w: S, xi: S, yj: S, zk: S) -> Quaternion { - Quaternion::from_sv(w, Vector3::new(xi, yj, zk)) - } - - /// Construct a new quaternion from a scalar and a vector. - #[inline] - pub const fn from_sv(s: S, v: Vector3) -> Quaternion { - Quaternion { s: s, v: v } - } -} - -impl Quaternion { - /// Construct a new quaternion as a closest arc between two vectors - /// - /// Return the closest rotation that turns `src` vector into `dst`. - /// - /// - [Related StackOverflow question] - /// (http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another) - /// - [Ogre implementation for normalized vectors] - /// (https://bitbucket.org/sinbad/ogre/src/9db75e3ba05c/OgreMain/include/OgreVector3.h?fileviewer=file-view-default#cl-651) - pub fn from_arc( - src: Vector3, - dst: Vector3, - fallback: Option>, - ) -> Quaternion { - let mag_avg = (src.magnitude2() * dst.magnitude2()).sqrt(); - let dot = src.dot(dst); - if ulps_eq!(dot, &mag_avg) { - Quaternion::::one() - } else if ulps_eq!(dot, &-mag_avg) { - let axis = fallback.unwrap_or_else(|| { - let mut v = Vector3::unit_x().cross(src); - if ulps_eq!(v, &Zero::zero()) { - v = Vector3::unit_y().cross(src); - } - v.normalize() - }); - Quaternion::from_axis_angle(axis, Rad::turn_div_2()) - } else { - Quaternion::from_sv(mag_avg + dot, src.cross(dst)).normalize() - } - } - - /// The conjugate of the quaternion. - #[inline] - pub fn conjugate(self) -> Quaternion { - Quaternion::from_sv(self.s, -self.v) - } - - /// Do a normalized linear interpolation with `other`, by `amount`. - pub fn nlerp(self, other: Quaternion, amount: S) -> Quaternion { - (self * (S::one() - amount) + other * amount).normalize() - } - - /// Spherical Linear Interpolation - /// - /// Return the spherical linear interpolation between the quaternion and - /// `other`. Both quaternions should be normalized first. - /// - /// # Performance notes - /// - /// The `acos` operation used in `slerp` is an expensive operation, so - /// unless your quaternions are far away from each other it's generally - /// more advisable to use `nlerp` when you know your rotations are going - /// to be small. - /// - /// - [Understanding Slerp, Then Not Using It] - /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/) - /// - [Arcsynthesis OpenGL tutorial] - /// (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html) - pub fn slerp(self, other: Quaternion, amount: S) -> Quaternion { - let dot = self.dot(other); - let dot_threshold = cast(0.9995f64).unwrap(); - - // if quaternions are close together use `nlerp` - if dot > dot_threshold { - self.nlerp(other, amount) - } else { - // stay within the domain of acos() - // TODO REMOVE WHEN https://github.com/mozilla/rust/issues/12068 IS RESOLVED - let robust_dot = if dot > S::one() { - S::one() - } else if dot < -S::one() { - -S::one() - } else { - dot - }; - - let theta = Rad::acos(robust_dot.clone()); - - let scale1 = Rad::sin(theta * (S::one() - amount)); - let scale2 = Rad::sin(theta * amount); - - (self * scale1 + other * scale2) * Rad::sin(theta).recip() - } - } - - pub fn is_finite(&self) -> bool { - self.s.is_finite() && self.v.is_finite() - } -} - -impl Zero for Quaternion { - #[inline] - fn zero() -> Quaternion { - Quaternion::from_sv(S::zero(), Vector3::zero()) - } - - #[inline] - fn is_zero(&self) -> bool { - ulps_eq!(self, &Quaternion::::zero()) - } -} - -impl One for Quaternion { - #[inline] - fn one() -> Quaternion { - Quaternion::from_sv(S::one(), Vector3::zero()) - } -} - -impl iter::Sum> for Quaternion { - #[inline] - fn sum>>(iter: I) -> Quaternion { - iter.fold(Quaternion::::zero(), Add::add) - } -} - -impl<'a, S: 'a + BaseFloat> iter::Sum<&'a Quaternion> for Quaternion { - #[inline] - fn sum>>(iter: I) -> Quaternion { - iter.fold(Quaternion::::zero(), Add::add) - } -} - -impl iter::Product> for Quaternion { - #[inline] - fn product>>(iter: I) -> Quaternion { - iter.fold(Quaternion::::one(), Mul::mul) - } -} - -impl<'a, S: 'a + BaseFloat> iter::Product<&'a Quaternion> for Quaternion { - #[inline] - fn product>>(iter: I) -> Quaternion { - iter.fold(Quaternion::::one(), Mul::mul) - } -} - -impl VectorSpace for Quaternion { - type Scalar = S; -} - -impl MetricSpace for Quaternion { - type Metric = S; - - #[inline] - fn distance2(self, other: Self) -> S { - (other - self).magnitude2() - } -} - -impl Quaternion { - /// Component-wise casting to another type. - pub fn cast(&self) -> Option> { - let s = match NumCast::from(self.s) { - Some(s) => s, - None => return None, - }; - let v = match self.v.cast() { - Some(v) => v, - None => return None, - }; - Some(Quaternion::from_sv(s, v)) - } -} - -#[cfg(not(feature = "simd"))] -impl InnerSpace for Quaternion { - #[inline] - fn dot(self, other: Quaternion) -> S { - self.s * other.s + self.v.dot(other.v) - } -} - -#[cfg(feature = "simd")] -impl InnerSpace for Quaternion { - #[inline] - default fn dot(self, other: Quaternion) -> S { - self.s * other.s + self.v.dot(other.v) - } -} - -#[cfg(feature = "simd")] -impl InnerSpace for Quaternion { - #[inline] - fn dot(self, other: Quaternion) -> f32 { - let lhs: Simdf32x4 = self.into(); - let rhs: Simdf32x4 = other.into(); - let r = lhs * rhs; - r.extract(0) + r.extract(1) + r.extract(2) + r.extract(3) - } -} - -impl From> for Quaternion -where - A: Angle + Into::Unitless>>, -{ - fn from(src: Euler) -> Quaternion { - // Euclidean Space has an Euler to quat equation, but it is for a different order (YXZ): - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm - // Page A-2 here has the formula for XYZ: - // http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf - - let half = cast(0.5f64).unwrap(); - let (s_x, c_x) = Rad::sin_cos(src.x.into() * half); - let (s_y, c_y) = Rad::sin_cos(src.y.into() * half); - let (s_z, c_z) = Rad::sin_cos(src.z.into() * half); - - Quaternion::new( - -s_x * s_y * s_z + c_x * c_y * c_z, - s_x * c_y * c_z + s_y * s_z * c_x, - -s_x * s_z * c_y + s_y * c_x * c_z, - s_x * s_y * c_z + s_z * c_x * c_y, - ) - } -} - -#[cfg(not(feature = "simd"))] -impl_operator!( Neg for Quaternion { - fn neg(quat) -> Quaternion { - Quaternion::from_sv(-quat.s, -quat.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_default!( Neg for Quaternion { - fn neg(quat) -> Quaternion { - Quaternion::from_sv(-quat.s, -quat.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Neg for Quaternion { - fn neg(lhs) -> Quaternion { - (-lhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] -impl_operator!( Mul for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) - } -}); - -#[cfg(feature = "simd")] -impl_operator_default!( Mul for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Mul for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - (lhs * rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] -impl_assignment_operator!( MulAssign for Quaternion { - fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } -}); - -#[cfg(feature = "simd")] -impl_assignment_operator_default!( MulAssign for Quaternion { - fn mul_assign(&mut self, scalar) { self.s *= scalar; self.v *= scalar; } -}); - -#[cfg(feature = "simd")] -impl MulAssign for Quaternion { - fn mul_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s * other).into(); - } -} - -#[cfg(not(feature = "simd"))] -impl_operator!( Div for Quaternion { - fn div(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) - } -}); - -#[cfg(feature = "simd")] -impl_operator_default!( Div for Quaternion { - fn div(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{@rs - [Simdf32x4]; Div for Quaternion { - fn div(lhs, rhs) -> Quaternion { - (lhs / rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] -impl_assignment_operator!( DivAssign for Quaternion { - fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } -}); - -#[cfg(feature = "simd")] -impl_assignment_operator_default!( DivAssign for Quaternion { - fn div_assign(&mut self, scalar) { self.s /= scalar; self.v /= scalar; } -}); - -#[cfg(feature = "simd")] -impl DivAssign for Quaternion { - fn div_assign(&mut self, other: f32) { - let s: Simdf32x4 = (*self).into(); - let other = Simdf32x4::splat(other); - *self = (s / other).into(); - } -} - -impl_operator!( Rem for Quaternion { - fn rem(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s % rhs, lhs.v % rhs) - } -}); - -impl_assignment_operator!( RemAssign for Quaternion { - fn rem_assign(&mut self, scalar) { self.s %= scalar; self.v %= scalar; } -}); - -impl_operator!( Mul > for Quaternion { - fn mul(lhs, rhs) -> Vector3 {{ - let rhs = rhs.clone(); - let two: S = cast(2i8).unwrap(); - let tmp = lhs.v.cross(rhs) + (rhs * lhs.s); - (lhs.v.cross(tmp) * two) + rhs - }} -}); - -#[cfg(not(feature = "simd"))] -impl_operator!( Add > for Quaternion { - fn add(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_default!( Add > for Quaternion { - fn add(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Add> for Quaternion { - fn add(lhs, rhs) -> Quaternion { - (lhs + rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] -impl_assignment_operator!( AddAssign > for Quaternion { - fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } -}); - -#[cfg(feature = "simd")] -impl_assignment_operator_default!( AddAssign > for Quaternion { - fn add_assign(&mut self, other) { self.s += other.s; self.v += other.v; } -}); - -#[cfg(feature = "simd")] -impl AddAssign for Quaternion { - #[inline] - fn add_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s + rhs).into(); - } -} - -#[cfg(not(feature = "simd"))] -impl_operator!( Sub > for Quaternion { - fn sub(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_default!( Sub > for Quaternion { - fn sub(lhs, rhs) -> Quaternion { - Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Sub> for Quaternion { - fn sub(lhs, rhs) -> Quaternion { - (lhs - rhs).into() - } - } -} - -#[cfg(not(feature = "simd"))] -impl_assignment_operator!( SubAssign > for Quaternion { - fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } -}); - -#[cfg(feature = "simd")] -impl_assignment_operator_default!( SubAssign > for Quaternion { - fn sub_assign(&mut self, other) { self.s -= other.s; self.v -= other.v; } -}); - -#[cfg(feature = "simd")] -impl SubAssign for Quaternion { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - let s: Simdf32x4 = (*self).into(); - let rhs: Simdf32x4 = rhs.into(); - *self = (s - rhs).into(); - } -} - -#[cfg(not(feature = "simd"))] -impl_operator!( Mul > for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::new( - lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, - lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, - lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, - lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x, - ) - } -}); - -#[cfg(feature = "simd")] -impl_operator_default!( Mul > for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - Quaternion::new( - lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, - lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, - lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, - lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x, - ) - } -}); - -#[cfg(feature = "simd")] -impl_operator_simd!{ - [Simdf32x4]; Mul> for Quaternion { - fn mul(lhs, rhs) -> Quaternion { - { - let p0 = Simdf32x4::splat(lhs.extract(0)) * rhs; - let p1 = Simdf32x4::splat(lhs.extract(1)) * Simdf32x4::new( - -rhs.extract(1), rhs.extract(0), -rhs.extract(3), rhs.extract(2) - ); - let p2 = Simdf32x4::splat(lhs.extract(2)) * Simdf32x4::new( - -rhs.extract(2), rhs.extract(3), rhs.extract(0), -rhs.extract(1) - ); - let p3 = Simdf32x4::splat(lhs.extract(3)) * Simdf32x4::new( - -rhs.extract(3), -rhs.extract(2), rhs.extract(1), rhs.extract(0) - ); - (p0 + p1 + p2 + p3).into() - } - } - } -} - -macro_rules! impl_scalar_mul { - ($S:ident) => { - impl_operator!(Mul> for $S { - fn mul(scalar, quat) -> Quaternion<$S> { - Quaternion::from_sv(scalar * quat.s, scalar * quat.v) - } - }); - }; -} - -macro_rules! impl_scalar_div { - ($S:ident) => { - impl_operator!(Div> for $S { - fn div(scalar, quat) -> Quaternion<$S> { - Quaternion::from_sv(scalar / quat.s, scalar / quat.v) - } - }); - }; -} - -impl_scalar_mul!(f32); -impl_scalar_mul!(f64); -impl_scalar_div!(f32); -impl_scalar_div!(f64); - -impl approx::AbsDiffEq for Quaternion { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - S::abs_diff_eq(&self.s, &other.s, epsilon) - && Vector3::abs_diff_eq(&self.v, &other.v, epsilon) - } -} - -impl approx::RelativeEq for Quaternion { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - S::relative_eq(&self.s, &other.s, epsilon, max_relative) - && Vector3::relative_eq(&self.v, &other.v, epsilon, max_relative) - } -} - -impl approx::UlpsEq for Quaternion { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - S::ulps_eq(&self.s, &other.s, epsilon, max_ulps) - && Vector3::ulps_eq(&self.v, &other.v, epsilon, max_ulps) - } -} - -impl From> for Matrix3 { - /// Convert the quaternion to a 3 x 3 rotation matrix. - fn from(quat: Quaternion) -> Matrix3 { - let x2 = quat.v.x + quat.v.x; - let y2 = quat.v.y + quat.v.y; - let z2 = quat.v.z + quat.v.z; - - let xx2 = x2 * quat.v.x; - let xy2 = x2 * quat.v.y; - let xz2 = x2 * quat.v.z; - - let yy2 = y2 * quat.v.y; - let yz2 = y2 * quat.v.z; - let zz2 = z2 * quat.v.z; - - let sy2 = y2 * quat.s; - let sz2 = z2 * quat.s; - let sx2 = x2 * quat.s; - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix3::new( - S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, - xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, - xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2, - ) - } -} - -impl From> for Matrix4 { - /// Convert the quaternion to a 4 x 4 rotation matrix. - fn from(quat: Quaternion) -> Matrix4 { - let x2 = quat.v.x + quat.v.x; - let y2 = quat.v.y + quat.v.y; - let z2 = quat.v.z + quat.v.z; - - let xx2 = x2 * quat.v.x; - let xy2 = x2 * quat.v.y; - let xz2 = x2 * quat.v.z; - - let yy2 = y2 * quat.v.y; - let yz2 = y2 * quat.v.z; - let zz2 = z2 * quat.v.z; - - let sy2 = y2 * quat.s; - let sz2 = z2 * quat.s; - let sx2 = x2 * quat.s; - - #[cfg_attr(rustfmt, rustfmt_skip)] - Matrix4::new( - S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, S::zero(), - xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, S::zero(), - xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2, S::zero(), - S::zero(), S::zero(), S::zero(), S::one(), - ) - } -} - -// Quaternion Rotation impls - -impl From> for Basis3 { - #[inline] - fn from(quat: Quaternion) -> Basis3 { - Basis3::from_quaternion(&quat) - } -} - -impl Rotation> for Quaternion { - #[inline] - fn look_at(dir: Vector3, up: Vector3) -> Quaternion { - Matrix3::look_at(dir, up).into() - } - - #[inline] - fn between_vectors(a: Vector3, b: Vector3) -> Quaternion { - // http://stackoverflow.com/a/11741520/2074937 see 'Half-Way Quaternion Solution' - - let k_cos_theta = a.dot(b); - - // same direction - if ulps_eq!(k_cos_theta, S::one()) { - return Quaternion::::one(); - } - - let k = (a.magnitude2() * b.magnitude2()).sqrt(); - - // opposite direction - if ulps_eq!(k_cos_theta / k, -S::one()) { - let mut orthogonal = a.cross(Vector3::unit_x()); - if ulps_eq!(orthogonal.magnitude2(), S::zero()) { - orthogonal = a.cross(Vector3::unit_y()); - } - return Quaternion::from_sv(S::zero(), orthogonal.normalize()); - } - - // any other direction - Quaternion::from_sv(k + k_cos_theta, a.cross(b)).normalize() - } - - #[inline] - fn rotate_vector(&self, vec: Vector3) -> Vector3 { - self * vec - } - - #[inline] - fn invert(&self) -> Quaternion { - self.conjugate() / self.magnitude2() - } -} - -impl Rotation3 for Quaternion { - #[inline] - fn from_axis_angle>>(axis: Vector3, angle: A) -> Quaternion { - let (s, c) = Rad::sin_cos(angle.into() * cast(0.5f64).unwrap()); - Quaternion::from_sv(c, axis * s) - } -} - -impl Into<[S; 4]> for Quaternion { - #[inline] - fn into(self) -> [S; 4] { - match self.into() { - (w, xi, yj, zk) => [w, xi, yj, zk], - } - } -} - -impl AsRef<[S; 4]> for Quaternion { - #[inline] - fn as_ref(&self) -> &[S; 4] { - unsafe { mem::transmute(self) } - } -} - -impl AsMut<[S; 4]> for Quaternion { - #[inline] - fn as_mut(&mut self) -> &mut [S; 4] { - unsafe { mem::transmute(self) } - } -} - -impl From<[S; 4]> for Quaternion { - #[inline] - fn from(v: [S; 4]) -> Quaternion { - Quaternion::new(v[0], v[1], v[2], v[3]) - } -} - -impl<'a, S: BaseFloat> From<&'a [S; 4]> for &'a Quaternion { - #[inline] - fn from(v: &'a [S; 4]) -> &'a Quaternion { - unsafe { mem::transmute(v) } - } -} - -impl<'a, S: BaseFloat> From<&'a mut [S; 4]> for &'a mut Quaternion { - #[inline] - fn from(v: &'a mut [S; 4]) -> &'a mut Quaternion { - unsafe { mem::transmute(v) } - } -} - -impl Into<(S, S, S, S)> for Quaternion { - #[inline] - fn into(self) -> (S, S, S, S) { - match self { - Quaternion { - s, - v: Vector3 { x, y, z }, - } => (s, x, y, z), - } - } -} - -impl AsRef<(S, S, S, S)> for Quaternion { - #[inline] - fn as_ref(&self) -> &(S, S, S, S) { - unsafe { mem::transmute(self) } - } -} - -impl AsMut<(S, S, S, S)> for Quaternion { - #[inline] - fn as_mut(&mut self) -> &mut (S, S, S, S) { - unsafe { mem::transmute(self) } - } -} - -impl From<(S, S, S, S)> for Quaternion { - #[inline] - fn from(v: (S, S, S, S)) -> Quaternion { - match v { - (w, xi, yj, zk) => Quaternion::new(w, xi, yj, zk), - } - } -} - -impl<'a, S: BaseFloat> From<&'a (S, S, S, S)> for &'a Quaternion { - #[inline] - fn from(v: &'a (S, S, S, S)) -> &'a Quaternion { - unsafe { mem::transmute(v) } - } -} - -impl<'a, S: BaseFloat> From<&'a mut (S, S, S, S)> for &'a mut Quaternion { - #[inline] - fn from(v: &'a mut (S, S, S, S)) -> &'a mut Quaternion { - unsafe { mem::transmute(v) } - } -} - -macro_rules! index_operators { - ($S:ident, $Output:ty, $I:ty) => { - impl<$S: BaseFloat> Index<$I> for Quaternion<$S> { - type Output = $Output; - - #[inline] - fn index<'a>(&'a self, i: $I) -> &'a $Output { - let v: &[$S; 4] = self.as_ref(); &v[i] - } - } - - impl<$S: BaseFloat> IndexMut<$I> for Quaternion<$S> { - #[inline] - fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { - let v: &mut [$S; 4] = self.as_mut(); &mut v[i] - } - } - } -} - -index_operators!(S, S, usize); -index_operators!(S, [S], Range); -index_operators!(S, [S], RangeTo); -index_operators!(S, [S], RangeFrom); -index_operators!(S, [S], RangeFull); - -impl Distribution> for Standard - where Standard: Distribution, - Standard: Distribution>, - S: BaseFloat { - #[inline] - fn sample(&self, rng: &mut R) -> Quaternion { - Quaternion::from_sv(rng.gen(), rng.gen()) - } -} - -#[cfg(feature = "mint")] -impl From> for Quaternion { - fn from(q: mint::Quaternion) -> Self { - Quaternion { - s: q.s, - v: q.v.into(), - } - } -} - -#[cfg(feature = "mint")] -impl Into> for Quaternion { - fn into(self) -> mint::Quaternion { - mint::Quaternion { - s: self.s, - v: self.v.into(), - } - } -} - -#[cfg(test)] -mod tests { - use quaternion::*; - use vector::*; - - const QUATERNION: Quaternion = Quaternion { - s: 1.0, - v: Vector3 { - x: 2.0, - y: 3.0, - z: 4.0, - }, - }; - - #[test] - fn test_into() { - let v = QUATERNION; - { - let v: [f32; 4] = v.into(); - assert_eq!(v, [1.0, 2.0, 3.0, 4.0]); - } - { - let v: (f32, f32, f32, f32) = v.into(); - assert_eq!(v, (1.0, 2.0, 3.0, 4.0)); - } - } - - #[test] - fn test_as_ref() { - let v = QUATERNION; - { - let v: &[f32; 4] = v.as_ref(); - assert_eq!(v, &[1.0, 2.0, 3.0, 4.0]); - } - { - let v: &(f32, f32, f32, f32) = v.as_ref(); - assert_eq!(v, &(1.0, 2.0, 3.0, 4.0)); - } - } - - #[test] - fn test_as_mut() { - let mut v = QUATERNION; - { - let v: &mut [f32; 4] = v.as_mut(); - assert_eq!(v, &mut [1.0, 2.0, 3.0, 4.0]); - } - { - let v: &mut (f32, f32, f32, f32) = v.as_mut(); - assert_eq!(v, &mut (1.0, 2.0, 3.0, 4.0)); - } - } - - #[test] - fn test_from() { - assert_eq!(Quaternion::from([1.0, 2.0, 3.0, 4.0]), QUATERNION); - { - let v = &[1.0, 2.0, 3.0, 4.0]; - let v: &Quaternion<_> = From::from(v); - assert_eq!(v, &QUATERNION); - } - { - let v = &mut [1.0, 2.0, 3.0, 4.0]; - let v: &mut Quaternion<_> = From::from(v); - assert_eq!(v, &QUATERNION); - } - assert_eq!(Quaternion::from((1.0, 2.0, 3.0, 4.0)), QUATERNION); - { - let v = &(1.0, 2.0, 3.0, 4.0); - let v: &Quaternion<_> = From::from(v); - assert_eq!(v, &QUATERNION); - } - { - let v = &mut (1.0, 2.0, 3.0, 4.0); - let v: &mut Quaternion<_> = From::from(v); - assert_eq!(v, &QUATERNION); - } - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/rotation.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/rotation.rs deleted file mode 100755 index 86a6ea5..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/rotation.rs +++ /dev/null @@ -1,451 +0,0 @@ -// Copyright 2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::fmt; -use std::iter; -use std::ops::*; - -use structure::*; - -use angle::Rad; -use approx; -use euler::Euler; -use matrix::{Matrix2, Matrix3}; -use num::BaseFloat; -use point::{Point2, Point3}; -use quaternion::Quaternion; -use vector::{Vector2, Vector3}; - -/// A trait for a generic rotation. A rotation is a transformation that -/// creates a circular motion, and preserves at least one point in the space. -pub trait Rotation: Sized + Copy + One -where - // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 - Self: approx::AbsDiffEq, - Self: approx::RelativeEq, - Self: approx::UlpsEq, - P::Scalar: BaseFloat, - Self: iter::Product, -{ - /// Create a rotation to a given direction with an 'up' vector. - fn look_at(dir: P::Diff, up: P::Diff) -> Self; - - /// Create a shortest rotation to transform vector 'a' into 'b'. - /// Both given vectors are assumed to have unit length. - fn between_vectors(a: P::Diff, b: P::Diff) -> Self; - - /// Rotate a vector using this rotation. - fn rotate_vector(&self, vec: P::Diff) -> P::Diff; - - /// Rotate a point using this rotation, by converting it to its - /// representation as a vector. - #[inline] - fn rotate_point(&self, point: P) -> P { - P::from_vec(self.rotate_vector(point.to_vec())) - } - - /// Create a new rotation which "un-does" this rotation. That is, - /// `r * r.invert()` is the identity. - fn invert(&self) -> Self; -} - -/// A two-dimensional rotation. -pub trait Rotation2 - : Rotation> + Into> + Into> { - /// Create a rotation by a given angle. Thus is a redundant case of both - /// from_axis_angle() and from_euler() for 2D space. - fn from_angle>>(theta: A) -> Self; -} - -/// A three-dimensional rotation. -pub trait Rotation3 - : Rotation> + Into> + Into> + Into> + From>> - { - /// Create a rotation using an angle around a given axis. - /// - /// The specified axis **must be normalized**, or it represents an invalid rotation. - fn from_axis_angle>>(axis: Vector3, angle: A) -> Self; - - /// Create a rotation from an angle around the `x` axis (pitch). - #[inline] - fn from_angle_x>>(theta: A) -> Self { - Rotation3::from_axis_angle(Vector3::unit_x(), theta) - } - - /// Create a rotation from an angle around the `y` axis (yaw). - #[inline] - fn from_angle_y>>(theta: A) -> Self { - Rotation3::from_axis_angle(Vector3::unit_y(), theta) - } - - /// Create a rotation from an angle around the `z` axis (roll). - #[inline] - fn from_angle_z>>(theta: A) -> Self { - Rotation3::from_axis_angle(Vector3::unit_z(), theta) - } -} - -/// A two-dimensional rotation matrix. -/// -/// The matrix is guaranteed to be orthogonal, so some operations can be -/// implemented more efficiently than the implementations for `math::Matrix2`. To -/// enforce orthogonality at the type level the operations have been restricted -/// to a subset of those implemented on `Matrix2`. -/// -/// ## Example -/// -/// Suppose we want to rotate a vector that lies in the x-y plane by some -/// angle. We can accomplish this quite easily with a two-dimensional rotation -/// matrix: -/// -/// ```no_run -/// use cgmath::Rad; -/// use cgmath::Vector2; -/// use cgmath::{Matrix, Matrix2}; -/// use cgmath::{Rotation, Rotation2, Basis2}; -/// use cgmath::UlpsEq; -/// use std::f64; -/// -/// // For simplicity, we will rotate the unit x vector to the unit y vector -- -/// // so the angle is 90 degrees, or π/2. -/// let unit_x: Vector2 = Vector2::unit_x(); -/// let rot: Basis2 = Rotation2::from_angle(Rad(0.5f64 * f64::consts::PI)); -/// -/// // Rotate the vector using the two-dimensional rotation matrix: -/// let unit_y = rot.rotate_vector(unit_x); -/// -/// // Since sin(π/2) may not be exactly zero due to rounding errors, we can -/// // use approx's assert_ulps_eq!() feature to show that it is close enough. -/// // assert_ulps_eq!(&unit_y, &Vector2::unit_y()); // TODO: Figure out how to use this -/// -/// // This is exactly equivalent to using the raw matrix itself: -/// let unit_y2: Matrix2<_> = rot.into(); -/// let unit_y2 = unit_y2 * unit_x; -/// assert_eq!(unit_y2, unit_y); -/// -/// // Note that we can also concatenate rotations: -/// let rot_half: Basis2 = Rotation2::from_angle(Rad(0.25f64 * f64::consts::PI)); -/// let unit_y3 = (rot_half * rot_half).rotate_vector(unit_x); -/// // assert_ulps_eq!(&unit_y3, &unit_y2); // TODO: Figure out how to use this -/// ``` -#[derive(PartialEq, Copy, Clone)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Basis2 { - mat: Matrix2, -} - -impl AsRef> for Basis2 { - #[inline] - fn as_ref(&self) -> &Matrix2 { - &self.mat - } -} - -impl From> for Matrix2 { - #[inline] - fn from(b: Basis2) -> Matrix2 { - b.mat - } -} - -impl iter::Product> for Basis2 { - #[inline] - fn product>>(iter: I) -> Basis2 { - iter.fold(Basis2::one(), Mul::mul) - } -} - -impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2> for Basis2 { - #[inline] - fn product>>(iter: I) -> Basis2 { - iter.fold(Basis2::one(), Mul::mul) - } -} - -impl Rotation> for Basis2 { - #[inline] - fn look_at(dir: Vector2, up: Vector2) -> Basis2 { - Basis2 { - mat: Matrix2::look_at(dir, up), - } - } - - #[inline] - fn between_vectors(a: Vector2, b: Vector2) -> Basis2 { - Rotation2::from_angle(Rad::acos(a.dot(b))) - } - - #[inline] - fn rotate_vector(&self, vec: Vector2) -> Vector2 { - self.mat * vec - } - - // TODO: we know the matrix is orthogonal, so this could be re-written - // to be faster - #[inline] - fn invert(&self) -> Basis2 { - Basis2 { - mat: self.mat.invert().unwrap(), - } - } -} - -impl One for Basis2 { - #[inline] - fn one() -> Basis2 { - Basis2 { - mat: Matrix2::one(), - } - } -} - -impl_operator!( Mul > for Basis2 { - fn mul(lhs, rhs) -> Basis2 { Basis2 { mat: lhs.mat * rhs.mat } } -}); - -impl approx::AbsDiffEq for Basis2 { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - Matrix2::abs_diff_eq(&self.mat, &other.mat, epsilon) - } -} - -impl approx::RelativeEq for Basis2 { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - Matrix2::relative_eq(&self.mat, &other.mat, epsilon, max_relative) - } -} - -impl approx::UlpsEq for Basis2 { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - Matrix2::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps) - } -} - -impl Rotation2 for Basis2 { - fn from_angle>>(theta: A) -> Basis2 { - Basis2 { - mat: Matrix2::from_angle(theta), - } - } -} - -impl fmt::Debug for Basis2 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Basis2 ")); - <[[S; 2]; 2] as fmt::Debug>::fmt(self.mat.as_ref(), f) - } -} - -/// A three-dimensional rotation matrix. -/// -/// The matrix is guaranteed to be orthogonal, so some operations, specifically -/// inversion, can be implemented more efficiently than the implementations for -/// `math::Matrix3`. To ensure orthogonality is maintained, the operations have -/// been restricted to a subset of those implemented on `Matrix3`. -#[derive(PartialEq, Copy, Clone)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Basis3 { - mat: Matrix3, -} - -impl Basis3 { - /// Create a new rotation matrix from a quaternion. - #[inline] - pub fn from_quaternion(quaternion: &Quaternion) -> Basis3 { - Basis3 { - mat: quaternion.clone().into(), - } - } -} - -impl AsRef> for Basis3 { - #[inline] - fn as_ref(&self) -> &Matrix3 { - &self.mat - } -} - -impl From> for Matrix3 { - #[inline] - fn from(b: Basis3) -> Matrix3 { - b.mat - } -} - -impl From> for Quaternion { - #[inline] - fn from(b: Basis3) -> Quaternion { - b.mat.into() - } -} - -impl iter::Product> for Basis3 { - #[inline] - fn product>>(iter: I) -> Basis3 { - iter.fold(Basis3::one(), Mul::mul) - } -} - -impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3> for Basis3 { - #[inline] - fn product>>(iter: I) -> Basis3 { - iter.fold(Basis3::one(), Mul::mul) - } -} - -impl Rotation> for Basis3 { - #[inline] - fn look_at(dir: Vector3, up: Vector3) -> Basis3 { - Basis3 { - mat: Matrix3::look_at(dir, up), - } - } - - #[inline] - fn between_vectors(a: Vector3, b: Vector3) -> Basis3 { - let q: Quaternion = Rotation::between_vectors(a, b); - q.into() - } - - #[inline] - fn rotate_vector(&self, vec: Vector3) -> Vector3 { - self.mat * vec - } - - // TODO: we know the matrix is orthogonal, so this could be re-written - // to be faster - #[inline] - fn invert(&self) -> Basis3 { - Basis3 { - mat: self.mat.invert().unwrap(), - } - } -} - -impl One for Basis3 { - #[inline] - fn one() -> Basis3 { - Basis3 { - mat: Matrix3::one(), - } - } -} - -impl_operator!( Mul > for Basis3 { - fn mul(lhs, rhs) -> Basis3 { Basis3 { mat: lhs.mat * rhs.mat } } -}); - -impl approx::AbsDiffEq for Basis3 { - type Epsilon = S::Epsilon; - - #[inline] - fn default_epsilon() -> S::Epsilon { - S::default_epsilon() - } - - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { - Matrix3::abs_diff_eq(&self.mat, &other.mat, epsilon) - } -} - -impl approx::RelativeEq for Basis3 { - #[inline] - fn default_max_relative() -> S::Epsilon { - S::default_max_relative() - } - - #[inline] - fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { - Matrix3::relative_eq(&self.mat, &other.mat, epsilon, max_relative) - } -} - -impl approx::UlpsEq for Basis3 { - #[inline] - fn default_max_ulps() -> u32 { - S::default_max_ulps() - } - - #[inline] - fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { - Matrix3::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps) - } -} - -impl Rotation3 for Basis3 { - fn from_axis_angle>>(axis: Vector3, angle: A) -> Basis3 { - Basis3 { - mat: Matrix3::from_axis_angle(axis, angle), - } - } - - fn from_angle_x>>(theta: A) -> Basis3 { - Basis3 { - mat: Matrix3::from_angle_x(theta), - } - } - - fn from_angle_y>>(theta: A) -> Basis3 { - Basis3 { - mat: Matrix3::from_angle_y(theta), - } - } - - fn from_angle_z>>(theta: A) -> Basis3 { - Basis3 { - mat: Matrix3::from_angle_z(theta), - } - } -} - -impl From> for Basis3 -where - A: Into::Unitless>>, -{ - /// Create a three-dimensional rotation matrix from a set of euler angles. - fn from(src: Euler) -> Basis3 { - Basis3 { - mat: Matrix3::from(src), - } - } -} - -impl fmt::Debug for Basis3 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "Basis3 ")); - <[[S; 3]; 3] as fmt::Debug>::fmt(self.mat.as_ref(), f) - } -} diff --git a/third_party/cargo/vendor/cgmath-0.17.0/src/transform.rs b/third_party/cargo/vendor/cgmath-0.17.0/src/transform.rs deleted file mode 100755 index f3d3113..0000000 --- a/third_party/cargo/vendor/cgmath-0.17.0/src/transform.rs +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2014 The CGMath Developers. For a full listing of the authors, -// refer to the Cargo.toml file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use structure::*; - -use approx; -use matrix::{Matrix2, Matrix3, Matrix4}; -use num::{BaseFloat, BaseNum}; -use point::{Point2, Point3}; -use rotation::*; -use vector::{Vector2, Vector3}; - -/// A trait representing an [affine -/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that -/// can be applied to points or vectors. An affine transformation is one which -pub trait Transform: Sized { - /// Create an identity transformation. That is, a transformation which - /// does nothing. - fn one() -> Self; - - /// Create a transformation that rotates a vector to look at `center` from - /// `eye`, using `up` for orientation. - fn look_at(eye: P, center: P, up: P::Diff) -> Self; - - /// Transform a vector using this transform. - fn transform_vector(&self, vec: P::Diff) -> P::Diff; - - /// Inverse transform a vector using this transform - fn inverse_transform_vector(&self, vec: P::Diff) -> Option { - self.inverse_transform() - .and_then(|inverse| Some(inverse.transform_vector(vec))) - } - - /// Transform a point using this transform. - fn transform_point(&self, point: P) -> P; - - /// Combine this transform with another, yielding a new transformation - /// which has the effects of both. - fn concat(&self, other: &Self) -> Self; - - /// Create a transform that "un-does" this one. - fn inverse_transform(&self) -> Option; - - /// Combine this transform with another, in-place. - #[inline] - fn concat_self(&mut self, other: &Self) { - *self = Self::concat(self, other); - } -} - -/// A generic transformation consisting of a rotation, -/// displacement vector and scale amount. -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Decomposed { - pub scale: V::Scalar, - pub rot: R, - pub disp: V, -} - -impl> Transform