diff options
author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/flume | |
parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/flume')
35 files changed, 15554 insertions, 0 deletions
diff --git a/vendor/flume/.cargo-checksum.json b/vendor/flume/.cargo-checksum.json new file mode 100644 index 0000000..b254421 --- /dev/null +++ b/vendor/flume/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"378edfec4dde51dee9c0d1e8285d88b3d218cb9b8b42ffa3e27405661c23b0b6","Cargo.lock":"cc14608e4a0c130f6f898cc6187e3b8964639f6c960bc9c08589dcac06506526","Cargo.toml":"6246515094dda94c71890606c39275b555aed886b5f4c789eb362ce7b1eea40f","LICENSE-APACHE":"d8621ec2eee5b9ca3c65f8492505f3590de8574fac0fdf5132a77232dba47abc","LICENSE-MIT":"30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652","README.md":"48f7ca4326cfcd3440931e5c82fc21f7b8a6f40041bc94be817c291ad71b6c5b","benches/basic.rs":"61ecb5f7c092b82382cc20e73ca84677dd4973cc358ea6bff15f92fda227b481","examples/async.rs":"7a0bb8848d94bd1fa9a857ffba0b3fbea6d57d7058ed65d2a7cbcf8518ec8652","examples/perf.rs":"52b67c619932a283ad9109c5fe5b47d32f7d3e7533356170047b686dfac330c9","examples/select.rs":"7659b015889545a59b9bce046fc353fea7bcaa9d54cb59f6bd5c002e15872909","examples/simple.rs":"f96d308b808b5fd66ca03dac9f09c13e5f13141992698551503415a411f6596a","src/async.rs":"851b0db2f8115eb222a9eb3c39d3dcdd8699c5b8e757580f26a03ca71c88d0e4","src/lib.rs":"36f84973b6bb45e54161dfb8eb574b30bace69d4b382e7fe8669d5636473d9ea","src/select.rs":"940cbdfbb26b9a2811bf42df3b26f1a619bd71896b8a6b6f2cdbb350c4fab270","src/signal.rs":"20a1732fdbfe888b9a25438bf16a185393f18fb1ad795926fae969c6817fe43b","tests/after.rs":"53e17263eab8eb733f575e4d1d43e054c6d22556d36e105f3f87c4cfb891880c","tests/array.rs":"2b071429d678e07ca52b79b4792120816a1ec7e64afd29c5781ddddbbbd7888b","tests/async.rs":"45bce43e990694578cf03c27dcf112df8d9ec1806e7c1be866885d76bb5abf85","tests/basic.rs":"0606408fe5ff1512839d43cc5c5f6a98c1e09fe919b5ad843643b5019926100b","tests/check_same_channel.rs":"e9e313d1ada50ac0ab0b9bcf19b901efd8cc226902edac62a8d573cea54e06ca","tests/golang.rs":"9e821cefd322a2353b288c7368902028daca643648da2e223ec1174c0e93e4ef","tests/iter.rs":"82d4f7acd20c9b10d2623211e71f5b6c37e4dafda2e13c871008c03995d76ced","tests/list.rs":"5885ee800d5c93b410d3bfa12d834fd817fd3362bca15a08b0aa7f84de58432e","tests/method_sharing.rs":"4d6c867e689254840ecbb1ae8a70ab3226d45bf92282e3bd2681c83726983ffa","tests/mpsc.rs":"965e18abbfcdebec09380f8ec9bb62e5556ad2aa0176ed088ce091994c1d2500","tests/never.rs":"cb838011c6f39c150c67e6836eb880300d53c22a2ea0312cdec999efb779ca29","tests/ready.rs":"5e1234ce49e8cbf89ec4f28bd2f4fe10641891bf6a7915d2fef6f9ab0c343997","tests/same_channel.rs":"71524e90dc364cc2c8085a9517757abe55f59a25b95600029abb283bc8677ad9","tests/select.rs":"67f8a647a7976f0d77673f4cc8d03b74690f3e8578c47e1bc64caeab68dd7df7","tests/select_macro.rs":"32793ac9775879e72ae3ce3975aa87f7407c6e7023d3d85f50f06a3ac5e308a3","tests/stream.rs":"c6d9500813d7216fd514f35dadb1b7b58282def553f40d76b37032221bb05cd6","tests/thread_locals.rs":"ad92e07a4ef5c3dd8b6ff8620161ab93963b3de241a680db551f2be60c8e3853","tests/tick.rs":"35fabd118073decf0cd830e9245c77a1a2e19227f7b4f73d239589728a591601","tests/zero.rs":"23a15a51681596716d5882242cd2c8cd0925c6ea2d0ef289f80775f3f2d6d10c"},"package":"55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"}
\ No newline at end of file diff --git a/vendor/flume/CHANGELOG.md b/vendor/flume/CHANGELOG.md new file mode 100644 index 0000000..14a604f --- /dev/null +++ b/vendor/flume/CHANGELOG.md @@ -0,0 +1,134 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +# Unreleased + +### Added + +### Removed + +### Changed + +### Fixed + +# [0.11.0] - 2023-08-16 + +### Added + +- `WeakSender`, a sender that doesn't keep the channel open +- `Sender/Receiver::sender_count/receiver_count`, a way to query the number of senders and receivers attached to a channel +- `Sender/Receiver::same_channel`, a way to determine whether senders and receivers are attached to the same channel + +### Changed + +- Relaxed some API features +- Make all remaining spinlocks opt-in + +### Fixed + +- Fixed a rare race condition in the async implementation + +# [0.10.14] - 2022-07-21 + +### Fixed + +- Fixed unbounded memory usage in `RecvFut::poll_inner` + +# [0.10.13] - 2022-06-10 + +### Added + +- `SendSink::sender`, to get the sender of a `SendSink` + +# [0.10.12] - 2022-03-10 + +### Changed + +- Updated `nanorand` to 0.7 + +# [0.10.11] - 2022-02-14 + +### Fixed + +- Out-of-order bug when using channels asynchronously + +# [0.10.10] - 2022-01-11 + +### Added + +- `From<SendError>` and `From<RecvError>` impls for other error types +- Marked futures as `#[must_use]` + +### Changes + +- Switched to scheduler-driven locking by default, with a `spin` feature to reenable the old behaviour +- Minor doc improvements + +# [0.10.9] - 2021-08-25 + +### Changed + +- Switched from `spinning_top` to `spin` + +# [0.10.8] - 2021-08-06 + +### Changed + +- Updated `nanorand` to `0.6` + +# [0.10.7] - 2021-06-10 + +### Fixed + +- Removed accidental nightly-only syntax + +# [0.10.6] - 2021-06-10 + +### Added + +- `fn into_inner(self) -> T` for send errors, allowing for easy access to the unsent message + +# [0.10.5] - 2021-04-26 + +### Added + +- `is_disconnected`, `is_empty`, `is_full`, `len`, and `capacity` on future types + +# [0.10.4] - 2021-04-12 + +### Fixed + +- Shutdown-related race condition with async recv that caused spurious errors + +# [0.10.3] - 2021-04-09 + +### Fixed + +- Compilation error when enabling `select` without `eventual_fairness` + +# [0.10.2] - 2021-02-07 + +### Fixed + +- Incorrect pointer comparison in `Selector` causing missing receives + +# [0.10.1] - 2020-12-30 + +### Removed + +- Removed `T: Unpin` requirement from async traits using `pin_project` + +# [0.10.0] - 2020-12-09 + +### Changed + +- Renamed `SendFuture` to `SendFut` to be consistent with `RecvFut` +- Improved async-related documentation + +### Fixed + +- Updated `nanorand` to address security advisory diff --git a/vendor/flume/Cargo.lock b/vendor/flume/Cargo.lock new file mode 100644 index 0000000..43921dd --- /dev/null +++ b/vendor/flume/Cargo.lock @@ -0,0 +1,1312 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +dependencies = [ + "memchr", +] + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +dependencies = [ + "async-io", + "async-lock", + "autocfg", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "signal-hook", + "windows-sys", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "async-process", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "log", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "errno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "flume" +version = "0.11.0" +dependencies = [ + "async-std", + "criterion", + "crossbeam-channel", + "crossbeam-utils", + "futures", + "futures-core", + "futures-sink", + "nanorand", + "rand", + "spin", + "tokio", + "waker-fn", +] + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.2", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[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.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.2", + "libc", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + +[[package]] +name = "pin-project-lite" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[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 = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tokio" +version = "1.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" +dependencies = [ + "backtrace", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "value-bag" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.28", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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 = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" diff --git a/vendor/flume/Cargo.toml b/vendor/flume/Cargo.toml new file mode 100644 index 0000000..4b4eca4 --- /dev/null +++ b/vendor/flume/Cargo.toml @@ -0,0 +1,110 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "flume" +version = "0.11.0" +authors = ["Joshua Barretto <joshua.s.barretto@gmail.com>"] +exclude = [ + "/.github", + "/misc", +] +description = "A blazingly fast multi-producer channel" +documentation = "https://docs.rs/flume" +readme = "README.md" +keywords = [ + "mpsc", + "fifo", + "channel", + "thread", + "mpmc", +] +categories = [ + "concurrency", + "data-structures", +] +license = "Apache-2.0/MIT" +repository = "https://github.com/zesterer/flume" + +[[bench]] +name = "basic" +harness = false + +[dependencies.futures-core] +version = "0.3" +optional = true +default_features = false + +[dependencies.futures-sink] +version = "0.3" +optional = true +default_features = false + +[dependencies.nanorand] +version = "0.7" +features = ["getrandom"] +optional = true + +[dependencies.spin1] +version = "0.9.8" +features = ["mutex"] +package = "spin" + +[dev-dependencies.async-std] +version = "1.9.0" +features = [ + "attributes", + "unstable", +] + +[dev-dependencies.criterion] +version = "0.3.4" + +[dev-dependencies.crossbeam-channel] +version = "0.5.5" + +[dev-dependencies.crossbeam-utils] +version = "0.8.10" + +[dev-dependencies.futures] +version = "^0.3" +features = ["std"] + +[dev-dependencies.rand] +version = "0.8.3" + +[dev-dependencies.tokio] +version = "^1.16.1" +features = [ + "rt", + "macros", +] + +[dev-dependencies.waker-fn] +version = "1.1.0" + +[features] +async = [ + "futures-sink", + "futures-core", +] +default = [ + "async", + "select", + "eventual-fairness", +] +eventual-fairness = [ + "select", + "nanorand", +] +select = [] +spin = [] diff --git a/vendor/flume/LICENSE-APACHE b/vendor/flume/LICENSE-APACHE new file mode 100644 index 0000000..f474855 --- /dev/null +++ b/vendor/flume/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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.
\ No newline at end of file diff --git a/vendor/flume/LICENSE-MIT b/vendor/flume/LICENSE-MIT new file mode 100644 index 0000000..468cd79 --- /dev/null +++ b/vendor/flume/LICENSE-MIT @@ -0,0 +1,23 @@ +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.
\ No newline at end of file diff --git a/vendor/flume/README.md b/vendor/flume/README.md new file mode 100644 index 0000000..d61155d --- /dev/null +++ b/vendor/flume/README.md @@ -0,0 +1,86 @@ +# Flume + +A blazingly fast multi-producer, multi-consumer channel. + +[![Cargo](https://img.shields.io/crates/v/flume.svg)]( +https://crates.io/crates/flume) +[![Documentation](https://docs.rs/flume/badge.svg)]( +https://docs.rs/flume) +[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( +https://github.com/zesterer/flume) +![actions-badge](https://github.com/zesterer/flume/workflows/Rust/badge.svg?branch=master) + +```rust +use std::thread; + +fn main() { + println!("Hello, world!"); + + let (tx, rx) = flume::unbounded(); + + thread::spawn(move || { + (0..10).for_each(|i| { + tx.send(i).unwrap(); + }) + }); + + let received: u32 = rx.iter().sum(); + + assert_eq!((0..10).sum::<u32>(), received); +} +``` + +## Why Flume? + +- **Featureful**: Unbounded, bounded and rendezvous queues +- **Fast**: Always faster than `std::sync::mpsc` and sometimes `crossbeam-channel` +- **Safe**: No `unsafe` code anywhere in the codebase! +- **Flexible**: `Sender` and `Receiver` both implement `Send + Sync + Clone` +- **Familiar**: Drop-in replacement for `std::sync::mpsc` +- **Capable**: Additional features like MPMC support and send timeouts/deadlines +- **Simple**: Few dependencies, minimal codebase, fast to compile +- **Asynchronous**: `async` support, including mix 'n match with sync code +- **Ergonomic**: Powerful `select`-like interface + +## Usage + +To use Flume, place the following line under the `[dependencies]` section in your `Cargo.toml`: + +```toml +flume = "x.y" +``` + +## Cargo Features + +Flume comes with several optional features: + +- `spin`: use spinlocks instead of OS-level synchronisation primitives internally for some kind of data access (may be more performant on a small number of platforms for specific workloads) + +- `select`: Adds support for the [`Selector`](https://docs.rs/flume/latest/flume/select/struct.Selector.html) API, allowing a thread to wait on several channels/operations at once + +- `async`: Adds support for the [async API](https://docs.rs/flume/latest/flume/async/index.html), including on otherwise synchronous channels + +- `eventual-fairness`: Use randomness in the implementation of `Selector` to avoid biasing/saturating certain events over others + +You can enable these features by changing the dependency in your `Cargo.toml` like so: + +```toml +flume = { version = "x.y", default-features = false, features = ["async", "select"] } +``` + +## [Benchmarks](https://what-if.xkcd.com/147/) + +Although Flume has its own extensive benchmarks, don't take it from here that Flume is quick. +The following graph is from the `crossbeam-channel` benchmark suite. + +Tests were performed on an AMD Ryzen 7 3700x with 8/16 cores running Linux kernel 5.11.2 with the bfq scheduler. + +# <img src="misc/benchmarks.png" alt="Flume benchmarks (crossbeam benchmark suite)" width="100%"/> + +## License + +Flume is licensed under either of: + +- Apache License 2.0, (http://www.apache.org/licenses/LICENSE-2.0) + +- MIT license (http://opensource.org/licenses/MIT) diff --git a/vendor/flume/benches/basic.rs b/vendor/flume/benches/basic.rs new file mode 100644 index 0000000..bbc4fc2 --- /dev/null +++ b/vendor/flume/benches/basic.rs @@ -0,0 +1,474 @@ +#[macro_use] +extern crate criterion; + +use std::{ + sync::mpsc, + thread, + fmt::Debug, +}; +use criterion::{Criterion, Bencher, black_box}; +use std::time::Instant; + +trait Sender: Clone + Send + Sized + 'static { + type Item: Debug + Default; + type BoundedSender: Sender<Item=Self::Item>; + type Receiver: Receiver<Item=Self::Item>; + + fn unbounded() -> (Self, Self::Receiver); + fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver); + fn send(&self, msg: Self::Item); +} + +trait Receiver: Send + Sized + 'static { + type Item: Default; + fn recv(&self) -> Self::Item; + fn iter(&self) -> Box<dyn Iterator<Item=Self::Item> + '_>; +} + +impl<T: Send + Debug + Default + 'static> Sender for flume::Sender<T> { + type Item = T; + type BoundedSender = Self; + type Receiver = flume::Receiver<T>; + + fn unbounded() -> (Self, Self::Receiver) { + flume::unbounded() + } + + fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) { + flume::bounded(n) + } + + fn send(&self, msg: T) { + flume::Sender::send(self, msg).unwrap(); + } +} + +impl<T: Send + Default + 'static> Receiver for flume::Receiver<T> { + type Item = T; + + fn recv(&self) -> Self::Item { + flume::Receiver::recv(self).unwrap() + } + + fn iter(&self) -> Box<dyn Iterator<Item=T> + '_> { + Box::new(std::iter::from_fn(move || flume::Receiver::recv(self).ok())) + } +} + +impl<T: Send + Debug + Default + 'static> Sender for crossbeam_channel::Sender<T> { + type Item = T; + type BoundedSender = Self; + type Receiver = crossbeam_channel::Receiver<T>; + + fn unbounded() -> (Self, Self::Receiver) { + crossbeam_channel::unbounded() + } + + fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) { + crossbeam_channel::bounded(n) + } + + fn send(&self, msg: T) { + crossbeam_channel::Sender::send(self, msg).unwrap(); + } +} + +impl<T: Send + Default + 'static> Receiver for crossbeam_channel::Receiver<T> { + type Item = T; + + fn recv(&self) -> Self::Item { + crossbeam_channel::Receiver::recv(self).unwrap() + } + + fn iter(&self) -> Box<dyn Iterator<Item=T> + '_> { + Box::new(crossbeam_channel::Receiver::iter(self)) + } +} + +impl<T: Send + Debug + Default + 'static> Sender for mpsc::Sender<T> { + type Item = T; + type BoundedSender = mpsc::SyncSender<T>; + type Receiver = mpsc::Receiver<T>; + + fn unbounded() -> (Self, Self::Receiver) { + mpsc::channel() + } + + fn bounded(n: usize) -> (Self::BoundedSender, Self::Receiver) { + mpsc::sync_channel(n) + } + + fn send(&self, msg: T) { + mpsc::Sender::send(self, msg).unwrap(); + } +} + +impl<T: Send + Debug + Default + 'static> Sender for mpsc::SyncSender<T> { + type Item = T; + type BoundedSender = Self; + type Receiver = mpsc::Receiver<T>; + + fn unbounded() -> (Self, Self::Receiver) { unimplemented!() } + fn bounded(_: usize) -> (Self::BoundedSender, Self::Receiver) { unimplemented!() } + + fn send(&self, msg: T) { + mpsc::SyncSender::send(self, msg).unwrap(); + } +} + +impl<T: Send + Default + 'static> Receiver for mpsc::Receiver<T> { + type Item = T; + + fn recv(&self) -> Self::Item { + mpsc::Receiver::recv(self).unwrap() + } + + fn iter(&self) -> Box<dyn Iterator<Item=T> + '_> { + Box::new(mpsc::Receiver::iter(self)) + } +} + +fn test_create<S: Sender>(b: &mut Bencher) { + b.iter(|| S::unbounded()); +} + +fn test_oneshot<S: Sender>(b: &mut Bencher) { + b.iter(|| { + let (tx, rx) = S::unbounded(); + tx.send(Default::default()); + black_box(rx.recv()); + }); +} + +fn test_inout<S: Sender>(b: &mut Bencher) { + let (tx, rx) = S::unbounded(); + b.iter(|| { + tx.send(Default::default()); + black_box(rx.recv()); + }); +} + +fn test_hydra<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) { + let (main_tx, main_rx) = S::unbounded(); + + let mut txs = Vec::new(); + for _ in 0..thread_num { + let main_tx = main_tx.clone(); + let (tx, rx) = S::unbounded(); + txs.push(tx); + + thread::spawn(move || { + for msg in rx.iter() { + main_tx.send(msg); + } + }); + } + + drop(main_tx); + + b.iter(|| { + for tx in &txs { + for _ in 0..msg_num { + tx.send(Default::default()); + } + } + + for _ in 0..thread_num { + for _ in 0..msg_num { + black_box(main_rx.recv()); + } + } + }); +} + +fn test_kitsune<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) + where S::Receiver: Clone +{ + let (out_tx, out_rx) = S::unbounded(); + let (in_tx, in_rx) = S::unbounded(); + + for _ in 0..thread_num { + let in_tx = in_tx.clone(); + let out_rx = out_rx.clone(); + + thread::spawn(move || { + for msg in out_rx.iter() { + in_tx.send(msg); + } + }); + } + + b.iter(|| { + for _ in 0..thread_num { + for _ in 0..msg_num { + out_tx.send(Default::default()); + } + } + + for _ in 0..thread_num { + for _ in 0..msg_num { + black_box(in_rx.recv()); + } + } + }); +} + +fn test_robin_u<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) { + let (mut main_tx, main_rx) = S::unbounded(); + + for _ in 0..thread_num { + let (mut tx, rx) = S::unbounded(); + std::mem::swap(&mut tx, &mut main_tx); + + thread::spawn(move || { + for msg in rx.iter() { + tx.send(msg); + } + }); + } + + b.iter(|| { + for _ in 0..msg_num { + main_tx.send(Default::default()); + } + + for _ in 0..msg_num { + black_box(main_rx.recv()); + } + }); +} + +fn test_robin_b<S: Sender>(b: &mut Bencher, thread_num: usize, msg_num: usize) { + let (mut main_tx, main_rx) = S::bounded(1); + + for _ in 0..thread_num { + let (mut tx, rx) = S::bounded(1); + std::mem::swap(&mut tx, &mut main_tx); + + thread::spawn(move || { + for msg in rx.iter() { + tx.send(msg); + } + }); + } + + b.iter(|| { + let main_tx = main_tx.clone(); + thread::spawn(move || { + for _ in 0..msg_num { + main_tx.send(Default::default()); + } + }); + + for _ in 0..msg_num { + black_box(main_rx.recv()); + } + }); +} + +fn test_mpsc_bounded_no_wait<S: Sender>(b: &mut Bencher, thread_num: u64) { + b.iter_custom(|iters| { + let iters = iters * 1000; + let (tx, rx) = S::bounded(iters as usize); + let start = Instant::now(); + + crossbeam_utils::thread::scope(|scope| { + for _ in 0..thread_num { + let tx = tx.clone(); + scope.spawn(move |_| { + for _ in 0..iters / thread_num { + tx.send(Default::default()); + } + }); + } + + for _ in 0..iters - ((iters / thread_num) * thread_num) { + tx.send(Default::default()); + } + + for _ in 0..iters { + black_box(rx.recv()); + } + }) + .unwrap(); + + start.elapsed() + }) +} + +fn test_mpsc_bounded<S: Sender>(b: &mut Bencher, bound: usize, thread_num: usize) { + b.iter_custom(|iters| { + let (tx, rx) = S::bounded(bound); + let start = Instant::now(); + + crossbeam_utils::thread::scope(|scope| { + let msgs = iters as usize * bound.max(1); + + for _ in 0..thread_num { + let tx = tx.clone(); + scope.spawn(move |_| { + for _ in 0..msgs / thread_num as usize { + tx.send(Default::default()); + } + }); + } + + scope.spawn(move |_| { + // Remainder + for _ in 0..msgs - (msgs / thread_num as usize * thread_num) { + tx.send(Default::default()); + } + }); + + for _ in 0..msgs { + black_box(rx.recv()); + } + }) + .unwrap(); + + start.elapsed() + }) +} + +fn create(b: &mut Criterion) { + b.bench_function("create-flume", |b| test_create::<flume::Sender<u32>>(b)); + b.bench_function("create-crossbeam", |b| test_create::<crossbeam_channel::Sender<u32>>(b)); + b.bench_function("create-std", |b| test_create::<mpsc::Sender<u32>>(b)); +} + +fn oneshot(b: &mut Criterion) { + b.bench_function("oneshot-flume", |b| test_oneshot::<flume::Sender<u32>>(b)); + b.bench_function("oneshot-crossbeam", |b| test_oneshot::<crossbeam_channel::Sender<u32>>(b)); + b.bench_function("oneshot-std", |b| test_oneshot::<mpsc::Sender<u32>>(b)); +} + +fn inout(b: &mut Criterion) { + b.bench_function("inout-flume", |b| test_inout::<flume::Sender<u32>>(b)); + b.bench_function("inout-crossbeam", |b| test_inout::<crossbeam_channel::Sender<u32>>(b)); + b.bench_function("inout-std", |b| test_inout::<mpsc::Sender<u32>>(b)); +} + +fn hydra_32t_1m(b: &mut Criterion) { + b.bench_function("hydra-32t-1m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 32, 1)); + b.bench_function("hydra-32t-1m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 32, 1)); + b.bench_function("hydra-32t-1m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 32, 1)); +} + +fn hydra_32t_1000m(b: &mut Criterion) { + b.bench_function("hydra-32t-1000m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 32, 1000)); + b.bench_function("hydra-32t-1000m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 32, 1000)); + b.bench_function("hydra-32t-1000m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 32, 1000)); +} + +fn hydra_256t_1m(b: &mut Criterion) { + b.bench_function("hydra-256t-1m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 256, 1)); + b.bench_function("hydra-256t-1m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 256, 1)); + b.bench_function("hydra-256t-1m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 256, 1)); +} + +fn hydra_1t_1000m(b: &mut Criterion) { + b.bench_function("hydra-1t-1000m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 1, 1000)); + b.bench_function("hydra-1t-1000m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 1, 1000)); + b.bench_function("hydra-1t-1000m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 1, 1000)); +} + +fn hydra_4t_10000m(b: &mut Criterion) { + b.bench_function("hydra-4t-10000m-flume", |b| test_hydra::<flume::Sender<u32>>(b, 4, 10000)); + b.bench_function("hydra-4t-10000m-crossbeam", |b| test_hydra::<crossbeam_channel::Sender<u32>>(b, 4, 10000)); + b.bench_function("hydra-4t-10000m-std", |b| test_hydra::<mpsc::Sender<u32>>(b, 4, 10000)); +} + +fn kitsune_32t_1m(b: &mut Criterion) { + b.bench_function("kitsune-32t-1m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 32, 1)); + b.bench_function("kitsune-32t-1m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 32, 1)); + //b.bench_function("kitsune-32t-1m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 32, 1)); +} + +fn kitsune_32t_1000m(b: &mut Criterion) { + b.bench_function("kitsune-32t-1000m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 32, 1000)); + b.bench_function("kitsune-32t-1000m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 32, 1000)); + //b.bench_function("kitsune-32t-1000m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 32, 1000)); +} + +fn kitsune_256t_1m(b: &mut Criterion) { + b.bench_function("kitsune-256t-1m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 256, 1)); + b.bench_function("kitsune-256t-1m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 256, 1)); + //b.bench_function("kitsune-256t-1m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 256, 1)); +} + +fn kitsune_1t_1000m(b: &mut Criterion) { + b.bench_function("kitsune-1t-1000m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 1, 1000)); + b.bench_function("kitsune-1t-1000m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 1, 1000)); + //b.bench_function("kitsune-1t-1000m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 1, 1000)); +} + +fn kitsune_4t_10000m(b: &mut Criterion) { + b.bench_function("kitsune-4t-10000m-flume", |b| test_kitsune::<flume::Sender<u32>>(b, 4, 10000)); + b.bench_function("kitsune-4t-10000m-crossbeam", |b| test_kitsune::<crossbeam_channel::Sender<u32>>(b, 4, 10000)); + //b.bench_function("kitsune-4t-10000m-std", |b| test_kitsune::<mpsc::Sender<u32>>(b, 4, 10000)); +} + +fn robin_u_32t_1m(b: &mut Criterion) { + b.bench_function("robin-u-32t-1m-flume", |b| test_robin_u::<flume::Sender<u32>>(b, 32, 1)); + b.bench_function("robin-u-32t-1m-crossbeam", |b| test_robin_u::<crossbeam_channel::Sender<u32>>(b, 32, 1)); + b.bench_function("robin-u-32t-1m-std", |b| test_robin_u::<mpsc::Sender<u32>>(b, 32, 1)); +} + +fn robin_u_4t_1000m(b: &mut Criterion) { + b.bench_function("robin-u-4t-1000m-flume", |b| test_robin_u::<flume::Sender<u32>>(b, 4, 1000)); + b.bench_function("robin-u-4t-1000m-crossbeam", |b| test_robin_u::<crossbeam_channel::Sender<u32>>(b, 4, 1000)); + b.bench_function("robin-u-4t-1000m-std", |b| test_robin_u::<mpsc::Sender<u32>>(b, 4, 1000)); +} + +fn robin_b_32t_16m(b: &mut Criterion) { + b.bench_function("robin-b-32t-16m-flume", |b| test_robin_b::<flume::Sender<u32>>(b, 32, 16)); + b.bench_function("robin-b-32t-16m-crossbeam", |b| test_robin_b::<crossbeam_channel::Sender<u32>>(b, 32, 16)); + b.bench_function("robin-b-32t-16m-std", |b| test_robin_b::<mpsc::Sender<u32>>(b, 32, 16)); +} + +fn robin_b_4t_1000m(b: &mut Criterion) { + b.bench_function("robin-b-4t-1000m-flume", |b| test_robin_b::<flume::Sender<u32>>(b, 4, 1000)); + b.bench_function("robin-b-4t-1000m-crossbeam", |b| test_robin_b::<crossbeam_channel::Sender<u32>>(b, 4, 1000)); + b.bench_function("robin-b-4t-1000m-std", |b| test_robin_b::<mpsc::Sender<u32>>(b, 4, 1000)); +} + +fn mpsc_bounded_no_wait_4t(b: &mut Criterion) { + b.bench_function("mpsc-bounded-no-wait-4t-flume", |b| test_mpsc_bounded_no_wait::<flume::Sender<u32>>(b, 4)); + b.bench_function("mpsc-bounded-no-wait-4t-crossbeam", |b| test_mpsc_bounded_no_wait::<crossbeam_channel::Sender<u32>>(b, 4)); + b.bench_function("mpsc-bounded-no-wait-4t-std", |b| test_mpsc_bounded_no_wait::<mpsc::Sender<u32>>(b, 4)); +} + +fn mpsc_bounded_4t(b: &mut Criterion) { + for bound in &[0, 1, 10, 50, 10_000] { + let text = format!("mpsc-bounded-small-4t-{}m-", bound); + let bound = *bound; + + b.bench_function(&format!("{}{}", text, "flume"), |b| test_mpsc_bounded::<flume::Sender<u32>>(b, bound, 4)); + b.bench_function(&format!("{}{}", text, "crossbeam"), |b| test_mpsc_bounded::<crossbeam_channel::Sender<u32>>(b, bound, 4)); + b.bench_function(&format!("{}{}", text, "std"), |b| test_mpsc_bounded::<mpsc::Sender<u32>>(b, bound, 4)); + } +} + +criterion_group!( + compare, + create, + oneshot, + inout, + hydra_32t_1m, + hydra_32t_1000m, + hydra_256t_1m, + hydra_1t_1000m, + hydra_4t_10000m, + robin_b_32t_16m, + robin_b_4t_1000m, + robin_u_32t_1m, + robin_u_4t_1000m, + mpsc_bounded_no_wait_4t, + mpsc_bounded_4t, + kitsune_32t_1m, + kitsune_32t_1000m, + kitsune_256t_1m, + kitsune_1t_1000m, + kitsune_4t_10000m, +); +criterion_main!(compare); diff --git a/vendor/flume/examples/async.rs b/vendor/flume/examples/async.rs new file mode 100644 index 0000000..a562700 --- /dev/null +++ b/vendor/flume/examples/async.rs @@ -0,0 +1,21 @@ +#[cfg(feature = "async")] +#[async_std::main] +async fn main() { + let (tx, rx) = flume::bounded(1); + + let t = async_std::task::spawn(async move { + while let Ok(msg) = rx.recv_async().await { + println!("Received: {}", msg); + } + }); + + tx.send_async("Hello, world!").await.unwrap(); + tx.send_async("How are you today?").await.unwrap(); + + drop(tx); + + t.await; +} + +#[cfg(not(feature = "async"))] +fn main() {} diff --git a/vendor/flume/examples/perf.rs b/vendor/flume/examples/perf.rs new file mode 100644 index 0000000..054dcbd --- /dev/null +++ b/vendor/flume/examples/perf.rs @@ -0,0 +1,30 @@ +fn main() { + let thread_num = 32; + let msg_num = 16; + + let (mut main_tx, main_rx) = flume::bounded::<()>(1); + + for _ in 0..thread_num { + let (mut tx, rx) = flume::bounded(1); + std::mem::swap(&mut tx, &mut main_tx); + + std::thread::spawn(move || { + for msg in rx.iter() { + tx.send(msg).unwrap(); + } + }); + } + + for _ in 0..1000 { + let main_tx = main_tx.clone(); + std::thread::spawn(move || { + for _ in 0..msg_num { + main_tx.send(Default::default()).unwrap(); + } + }); + + for _ in 0..msg_num { + main_rx.recv().unwrap(); + } + } +} diff --git a/vendor/flume/examples/select.rs b/vendor/flume/examples/select.rs new file mode 100644 index 0000000..bbe957b --- /dev/null +++ b/vendor/flume/examples/select.rs @@ -0,0 +1,25 @@ +#[cfg(feature = "select")] +use flume::Selector; + +#[cfg(feature = "select")] +fn main() { + // Create two channels + let (red_tx, red_rx) = flume::unbounded(); + let (blue_tx, blue_rx) = flume::unbounded(); + + // Spawn two threads that each send a message into their respective channel + std::thread::spawn(move || { let _ = red_tx.send("Red"); }); + std::thread::spawn(move || { let _ = blue_tx.send("Blue"); }); + + // Race them to see which one sends their message first + let winner = Selector::new() + .recv(&red_rx, |msg| msg) + .recv(&blue_rx, |msg| msg) + .wait() + .unwrap(); + + println!("{} won!", winner); +} + +#[cfg(not(feature = "select"))] +fn main() {} diff --git a/vendor/flume/examples/simple.rs b/vendor/flume/examples/simple.rs new file mode 100644 index 0000000..39cb1bd --- /dev/null +++ b/vendor/flume/examples/simple.rs @@ -0,0 +1,18 @@ +use std::thread; + +fn main() { + let (tx, rx) = flume::unbounded(); + + let t = thread::spawn(move || { + for msg in rx.iter() { + println!("Received: {}", msg); + } + }); + + tx.send("Hello, world!").unwrap(); + tx.send("How are you today?").unwrap(); + + drop(tx); + + t.join().unwrap(); +} diff --git a/vendor/flume/src/async.rs b/vendor/flume/src/async.rs new file mode 100644 index 0000000..fae44d4 --- /dev/null +++ b/vendor/flume/src/async.rs @@ -0,0 +1,543 @@ +//! Futures and other types that allow asynchronous interaction with channels. + +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll, Waker}, + any::Any, + ops::Deref, +}; +use crate::*; +use futures_core::{stream::{Stream, FusedStream}, future::FusedFuture}; +use futures_sink::Sink; +use spin1::Mutex as Spinlock; + +struct AsyncSignal { + waker: Spinlock<Waker>, + woken: AtomicBool, + stream: bool, +} + +impl AsyncSignal { + fn new(cx: &Context, stream: bool) -> Self { + AsyncSignal { + waker: Spinlock::new(cx.waker().clone()), + woken: AtomicBool::new(false), + stream, + } + } +} + +impl Signal for AsyncSignal { + fn fire(&self) -> bool { + self.woken.store(true, Ordering::SeqCst); + self.waker.lock().wake_by_ref(); + self.stream + } + + fn as_any(&self) -> &(dyn Any + 'static) { self } + fn as_ptr(&self) -> *const () { self as *const _ as *const () } +} + +impl<T> Hook<T, AsyncSignal> { + // Update the hook to point to the given Waker. + // Returns whether the hook has been previously awakened + fn update_waker(&self, cx_waker: &Waker) -> bool { + let mut waker = self.1.waker.lock(); + let woken = self.1.woken.load(Ordering::SeqCst); + if !waker.will_wake(cx_waker) { + *waker = cx_waker.clone(); + + // Avoid the edge case where the waker was woken just before the wakers were + // swapped. + if woken { + cx_waker.wake_by_ref(); + } + } + woken + } +} + +#[derive(Clone)] +enum OwnedOrRef<'a, T> { + Owned(T), + Ref(&'a T), +} + +impl<'a, T> Deref for OwnedOrRef<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + match self { + OwnedOrRef::Owned(arc) => &arc, + OwnedOrRef::Ref(r) => r, + } + } +} + +impl<T> Sender<T> { + /// Asynchronously send a value into the channel, returning an error if all receivers have been + /// dropped. If the channel is bounded and is full, the returned future will yield to the async + /// runtime. + /// + /// In the current implementation, the returned future will not yield to the async runtime if the + /// channel is unbounded. This may change in later versions. + pub fn send_async(&self, item: T) -> SendFut<T> { + SendFut { + sender: OwnedOrRef::Ref(&self), + hook: Some(SendState::NotYetSent(item)), + } + } + + /// Convert this sender into a future that asynchronously sends a single message into the channel, + /// returning an error if all receivers have been dropped. If the channel is bounded and is full, + /// this future will yield to the async runtime. + /// + /// In the current implementation, the returned future will not yield to the async runtime if the + /// channel is unbounded. This may change in later versions. + pub fn into_send_async<'a>(self, item: T) -> SendFut<'a, T> { + SendFut { + sender: OwnedOrRef::Owned(self), + hook: Some(SendState::NotYetSent(item)), + } + } + + /// Create an asynchronous sink that uses this sender to asynchronously send messages into the + /// channel. The sender will continue to be usable after the sink has been dropped. + /// + /// In the current implementation, the returned sink will not yield to the async runtime if the + /// channel is unbounded. This may change in later versions. + pub fn sink(&self) -> SendSink<'_, T> { + SendSink(SendFut { + sender: OwnedOrRef::Ref(&self), + hook: None, + }) + } + + /// Convert this sender into a sink that allows asynchronously sending messages into the channel. + /// + /// In the current implementation, the returned sink will not yield to the async runtime if the + /// channel is unbounded. This may change in later versions. + pub fn into_sink<'a>(self) -> SendSink<'a, T> { + SendSink(SendFut { + sender: OwnedOrRef::Owned(self), + hook: None, + }) + } +} + +enum SendState<T> { + NotYetSent(T), + QueuedItem(Arc<Hook<T, AsyncSignal>>), +} + +/// A future that sends a value into a channel. +/// +/// Can be created via [`Sender::send_async`] or [`Sender::into_send_async`]. +#[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"] +pub struct SendFut<'a, T> { + sender: OwnedOrRef<'a, Sender<T>>, + // Only none after dropping + hook: Option<SendState<T>>, +} + +impl<T> std::marker::Unpin for SendFut<'_, T> {} + +impl<'a, T> SendFut<'a, T> { + /// Reset the hook, clearing it and removing it from the waiting sender's queue. This is called + /// on drop and just before `start_send` in the `Sink` implementation. + fn reset_hook(&mut self) { + if let Some(SendState::QueuedItem(hook)) = self.hook.take() { + let hook: Arc<Hook<T, dyn Signal>> = hook; + wait_lock(&self.sender.shared.chan).sending + .as_mut() + .unwrap().1 + .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); + } + } + + /// See [`Sender::is_disconnected`]. + pub fn is_disconnected(&self) -> bool { + self.sender.is_disconnected() + } + + /// See [`Sender::is_empty`]. + pub fn is_empty(&self) -> bool { + self.sender.is_empty() + } + + /// See [`Sender::is_full`]. + pub fn is_full(&self) -> bool { + self.sender.is_full() + } + + /// See [`Sender::len`]. + pub fn len(&self) -> usize { + self.sender.len() + } + + /// See [`Sender::capacity`]. + pub fn capacity(&self) -> Option<usize> { + self.sender.capacity() + } +} + +impl<'a, T> Drop for SendFut<'a, T> { + fn drop(&mut self) { + self.reset_hook() + } +} + + +impl<'a, T> Future for SendFut<'a, T> { + type Output = Result<(), SendError<T>>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + if let Some(SendState::QueuedItem(hook)) = self.hook.as_ref() { + if hook.is_empty() { + Poll::Ready(Ok(())) + } else if self.sender.shared.is_disconnected() { + let item = hook.try_take(); + self.hook = None; + match item { + Some(item) => Poll::Ready(Err(SendError(item))), + None => Poll::Ready(Ok(())), + } + } else { + hook.update_waker(cx.waker()); + Poll::Pending + } + } else if let Some(SendState::NotYetSent(item)) = self.hook.take() { + let this = self.get_mut(); + let (shared, this_hook) = (&this.sender.shared, &mut this.hook); + + shared.send( + // item + item, + // should_block + true, + // make_signal + |msg| Hook::slot(Some(msg), AsyncSignal::new(cx, false)), + // do_block + |hook| { + *this_hook = Some(SendState::QueuedItem(hook)); + Poll::Pending + }, + ) + .map(|r| r.map_err(|err| match err { + TrySendTimeoutError::Disconnected(msg) => SendError(msg), + _ => unreachable!(), + })) + } else { // Nothing to do + Poll::Ready(Ok(())) + } + } +} + +impl<'a, T> FusedFuture for SendFut<'a, T> { + fn is_terminated(&self) -> bool { + self.sender.shared.is_disconnected() + } +} + +/// A sink that allows sending values into a channel. +/// +/// Can be created via [`Sender::sink`] or [`Sender::into_sink`]. +pub struct SendSink<'a, T>(SendFut<'a, T>); + +impl<'a, T> SendSink<'a, T> { + /// Returns a clone of a sending half of the channel of this sink. + pub fn sender(&self) -> &Sender<T> { + &self.0.sender + } + + /// See [`Sender::is_disconnected`]. + pub fn is_disconnected(&self) -> bool { + self.0.is_disconnected() + } + + /// See [`Sender::is_empty`]. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// See [`Sender::is_full`]. + pub fn is_full(&self) -> bool { + self.0.is_full() + } + + /// See [`Sender::len`]. + pub fn len(&self) -> usize { + self.0.len() + } + + /// See [`Sender::capacity`]. + pub fn capacity(&self) -> Option<usize> { + self.0.capacity() + } + + /// Returns whether the SendSinks are belong to the same channel. + pub fn same_channel(&self, other: &Self) -> bool { + self.sender().same_channel(other.sender()) + } +} + +impl<'a, T> Sink<T> for SendSink<'a, T> { + type Error = SendError<T>; + + fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> { + Pin::new(&mut self.0).poll(cx) + } + + fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { + self.0.reset_hook(); + self.0.hook = Some(SendState::NotYetSent(item)); + + Ok(()) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> { + Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here? + } + + fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> { + Pin::new(&mut self.0).poll(cx) // TODO: A different strategy here? + } +} + +impl<'a, T> Clone for SendSink<'a, T> { + fn clone(&self) -> SendSink<'a, T> { + SendSink(SendFut { + sender: self.0.sender.clone(), + hook: None, + }) + } +} + +impl<T> Receiver<T> { + /// Asynchronously receive a value from the channel, returning an error if all senders have been + /// dropped. If the channel is empty, the returned future will yield to the async runtime. + pub fn recv_async(&self) -> RecvFut<'_, T> { + RecvFut::new(OwnedOrRef::Ref(self)) + } + + /// Convert this receiver into a future that asynchronously receives a single message from the + /// channel, returning an error if all senders have been dropped. If the channel is empty, this + /// future will yield to the async runtime. + pub fn into_recv_async<'a>(self) -> RecvFut<'a, T> { + RecvFut::new(OwnedOrRef::Owned(self)) + } + + /// Create an asynchronous stream that uses this receiver to asynchronously receive messages + /// from the channel. The receiver will continue to be usable after the stream has been dropped. + pub fn stream(&self) -> RecvStream<'_, T> { + RecvStream(RecvFut::new(OwnedOrRef::Ref(self))) + } + + /// Convert this receiver into a stream that allows asynchronously receiving messages from the channel. + pub fn into_stream<'a>(self) -> RecvStream<'a, T> { + RecvStream(RecvFut::new(OwnedOrRef::Owned(self))) + } +} + +/// A future which allows asynchronously receiving a message. +/// +/// Can be created via [`Receiver::recv_async`] or [`Receiver::into_recv_async`]. +#[must_use = "futures/streams/sinks do nothing unless you `.await` or poll them"] +pub struct RecvFut<'a, T> { + receiver: OwnedOrRef<'a, Receiver<T>>, + hook: Option<Arc<Hook<T, AsyncSignal>>>, +} + +impl<'a, T> RecvFut<'a, T> { + fn new(receiver: OwnedOrRef<'a, Receiver<T>>) -> Self { + Self { + receiver, + hook: None, + } + } + + /// Reset the hook, clearing it and removing it from the waiting receivers queue and waking + /// another receiver if this receiver has been woken, so as not to cause any missed wakeups. + /// This is called on drop and after a new item is received in `Stream::poll_next`. + fn reset_hook(&mut self) { + if let Some(hook) = self.hook.take() { + let hook: Arc<Hook<T, dyn Signal>> = hook; + let mut chan = wait_lock(&self.receiver.shared.chan); + // We'd like to use `Arc::ptr_eq` here but it doesn't seem to work consistently with wide pointers? + chan.waiting.retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); + if hook.signal().as_any().downcast_ref::<AsyncSignal>().unwrap().woken.load(Ordering::SeqCst) { + // If this signal has been fired, but we're being dropped (and so not listening to it), + // pass the signal on to another receiver + chan.try_wake_receiver_if_pending(); + } + } + } + + fn poll_inner( + self: Pin<&mut Self>, + cx: &mut Context, + stream: bool, + ) -> Poll<Result<T, RecvError>> { + if self.hook.is_some() { + match self.receiver.shared.recv_sync(None) { + Ok(msg) => return Poll::Ready(Ok(msg)), + Err(TryRecvTimeoutError::Disconnected) => { + return Poll::Ready(Err(RecvError::Disconnected)) + } + _ => (), + } + + let hook = self.hook.as_ref().map(Arc::clone).unwrap(); + if hook.update_waker(cx.waker()) { + // If the previous hook was awakened, we need to insert it back to the + // queue, otherwise, it remains valid. + wait_lock(&self.receiver.shared.chan) + .waiting + .push_back(hook); + } + // To avoid a missed wakeup, re-check disconnect status here because the channel might have + // gotten shut down before we had a chance to push our hook + if self.receiver.shared.is_disconnected() { + // And now, to avoid a race condition between the first recv attempt and the disconnect check we + // just performed, attempt to recv again just in case we missed something. + Poll::Ready( + self.receiver + .shared + .recv_sync(None) + .map(Ok) + .unwrap_or(Err(RecvError::Disconnected)), + ) + } else { + Poll::Pending + } + } else { + let mut_self = self.get_mut(); + let (shared, this_hook) = (&mut_self.receiver.shared, &mut mut_self.hook); + + shared.recv( + // should_block + true, + // make_signal + || Hook::trigger(AsyncSignal::new(cx, stream)), + // do_block + |hook| { + *this_hook = Some(hook); + Poll::Pending + }, + ) + .map(|r| r.map_err(|err| match err { + TryRecvTimeoutError::Disconnected => RecvError::Disconnected, + _ => unreachable!(), + })) + } + } + + /// See [`Receiver::is_disconnected`]. + pub fn is_disconnected(&self) -> bool { + self.receiver.is_disconnected() + } + + /// See [`Receiver::is_empty`]. + pub fn is_empty(&self) -> bool { + self.receiver.is_empty() + } + + /// See [`Receiver::is_full`]. + pub fn is_full(&self) -> bool { + self.receiver.is_full() + } + + /// See [`Receiver::len`]. + pub fn len(&self) -> usize { + self.receiver.len() + } + + /// See [`Receiver::capacity`]. + pub fn capacity(&self) -> Option<usize> { + self.receiver.capacity() + } +} + +impl<'a, T> Drop for RecvFut<'a, T> { + fn drop(&mut self) { + self.reset_hook(); + } +} + +impl<'a, T> Future for RecvFut<'a, T> { + type Output = Result<T, RecvError>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + self.poll_inner(cx, false) // stream = false + } +} + +impl<'a, T> FusedFuture for RecvFut<'a, T> { + fn is_terminated(&self) -> bool { + self.receiver.shared.is_disconnected() && self.receiver.shared.is_empty() + } +} + +/// A stream which allows asynchronously receiving messages. +/// +/// Can be created via [`Receiver::stream`] or [`Receiver::into_stream`]. +pub struct RecvStream<'a, T>(RecvFut<'a, T>); + +impl<'a, T> RecvStream<'a, T> { + /// See [`Receiver::is_disconnected`]. + pub fn is_disconnected(&self) -> bool { + self.0.is_disconnected() + } + + /// See [`Receiver::is_empty`]. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// See [`Receiver::is_full`]. + pub fn is_full(&self) -> bool { + self.0.is_full() + } + + /// See [`Receiver::len`]. + pub fn len(&self) -> usize { + self.0.len() + } + + /// See [`Receiver::capacity`]. + pub fn capacity(&self) -> Option<usize> { + self.0.capacity() + } + + /// Returns whether the SendSinks are belong to the same channel. + pub fn same_channel(&self, other: &Self) -> bool { + self.0.receiver.same_channel(&*other.0.receiver) + } +} + +impl<'a, T> Clone for RecvStream<'a, T> { + fn clone(&self) -> RecvStream<'a, T> { + RecvStream(RecvFut::new(self.0.receiver.clone())) + } +} + +impl<'a, T> Stream for RecvStream<'a, T> { + type Item = T; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { + match Pin::new(&mut self.0).poll_inner(cx, true) { // stream = true + Poll::Pending => Poll::Pending, + Poll::Ready(item) => { + self.0.reset_hook(); + Poll::Ready(item.ok()) + } + } + } +} + +impl<'a, T> FusedStream for RecvStream<'a, T> { + fn is_terminated(&self) -> bool { + self.0.is_terminated() + } +} diff --git a/vendor/flume/src/lib.rs b/vendor/flume/src/lib.rs new file mode 100644 index 0000000..c9bb3ee --- /dev/null +++ b/vendor/flume/src/lib.rs @@ -0,0 +1,1142 @@ +//! # Flume +//! +//! A blazingly fast multi-producer, multi-consumer channel. +//! +//! *"Do not communicate by sharing memory; instead, share memory by communicating."* +//! +//! ## Why Flume? +//! +//! - **Featureful**: Unbounded, bounded and rendezvous queues +//! - **Fast**: Always faster than `std::sync::mpsc` and sometimes `crossbeam-channel` +//! - **Safe**: No `unsafe` code anywhere in the codebase! +//! - **Flexible**: `Sender` and `Receiver` both implement `Send + Sync + Clone` +//! - **Familiar**: Drop-in replacement for `std::sync::mpsc` +//! - **Capable**: Additional features like MPMC support and send timeouts/deadlines +//! - **Simple**: Few dependencies, minimal codebase, fast to compile +//! - **Asynchronous**: `async` support, including mix 'n match with sync code +//! - **Ergonomic**: Powerful `select`-like interface +//! +//! ## Example +//! +//! ``` +//! let (tx, rx) = flume::unbounded(); +//! +//! tx.send(42).unwrap(); +//! assert_eq!(rx.recv().unwrap(), 42); +//! ``` + +#![deny(missing_docs)] + +#[cfg(feature = "select")] +pub mod select; +#[cfg(feature = "async")] +pub mod r#async; + +mod signal; + +// Reexports +#[cfg(feature = "select")] +pub use select::Selector; + +use std::{ + collections::VecDeque, + sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}, Weak}, + time::{Duration, Instant}, + marker::PhantomData, + thread, + fmt, +}; + +#[cfg(feature = "spin")] +use spin1::{Mutex as Spinlock, MutexGuard as SpinlockGuard}; +use crate::signal::{Signal, SyncSignal}; + +/// An error that may be emitted when attempting to send a value into a channel on a sender when +/// all receivers are dropped. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct SendError<T>(pub T); + +impl<T> SendError<T> { + /// Consume the error, yielding the message that failed to send. + pub fn into_inner(self) -> T { self.0 } +} + +impl<T> fmt::Debug for SendError<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "SendError(..)".fmt(f) + } +} + +impl<T> fmt::Display for SendError<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "sending on a closed channel".fmt(f) + } +} + +impl<T> std::error::Error for SendError<T> {} + +/// An error that may be emitted when attempting to send a value into a channel on a sender when +/// the channel is full or all receivers are dropped. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum TrySendError<T> { + /// The channel the message is sent on has a finite capacity and was full when the send was attempted. + Full(T), + /// All channel receivers were dropped and so the message has nobody to receive it. + Disconnected(T), +} + +impl<T> TrySendError<T> { + /// Consume the error, yielding the message that failed to send. + pub fn into_inner(self) -> T { + match self { + Self::Full(msg) | Self::Disconnected(msg) => msg, + } + } +} + +impl<T> fmt::Debug for TrySendError<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TrySendError::Full(..) => "Full(..)".fmt(f), + TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + } + } +} + +impl<T> fmt::Display for TrySendError<T> { + 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 closed channel".fmt(f), + } + } +} + +impl<T> std::error::Error for TrySendError<T> {} + +impl<T> From<SendError<T>> for TrySendError<T> { + fn from(err: SendError<T>) -> Self { + match err { + SendError(item) => Self::Disconnected(item), + } + } +} + +/// An error that may be emitted when sending a value into a channel on a sender with a timeout when +/// the send operation times out or all receivers are dropped. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum SendTimeoutError<T> { + /// A timeout occurred when attempting to send the message. + Timeout(T), + /// All channel receivers were dropped and so the message has nobody to receive it. + Disconnected(T), +} + +impl<T> SendTimeoutError<T> { + /// Consume the error, yielding the message that failed to send. + pub fn into_inner(self) -> T { + match self { + Self::Timeout(msg) | Self::Disconnected(msg) => msg, + } + } +} + +impl<T> fmt::Debug for SendTimeoutError<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "SendTimeoutError(..)".fmt(f) + } +} + +impl<T> fmt::Display for SendTimeoutError<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SendTimeoutError::Timeout(..) => "timed out sending on a full channel".fmt(f), + SendTimeoutError::Disconnected(..) => "sending on a closed channel".fmt(f), + } + } +} + +impl<T> std::error::Error for SendTimeoutError<T> {} + +impl<T> From<SendError<T>> for SendTimeoutError<T> { + fn from(err: SendError<T>) -> Self { + match err { + SendError(item) => Self::Disconnected(item), + } + } +} + +enum TrySendTimeoutError<T> { + Full(T), + Disconnected(T), + Timeout(T), +} + +/// An error that may be emitted when attempting to wait for a value on a receiver when all senders +/// are dropped and there are no more messages in the channel. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RecvError { + /// All senders were dropped and no messages are waiting in the channel, so no further messages can be received. + Disconnected, +} + +impl fmt::Display for RecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RecvError::Disconnected => "receiving on a closed channel".fmt(f), + } + } +} + +impl std::error::Error for RecvError {} + +/// An error that may be emitted when attempting to fetch a value on a receiver when there are no +/// messages in the channel. If there are no messages in the channel and all senders are dropped, +/// then `TryRecvError::Disconnected` will be returned. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum TryRecvError { + /// The channel was empty when the receive was attempted. + Empty, + /// All senders were dropped and no messages are waiting in the channel, so no further messages can be received. + Disconnected, +} + +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 => "channel is empty and closed".fmt(f), + } + } +} + +impl std::error::Error for TryRecvError {} + +impl From<RecvError> for TryRecvError { + fn from(err: RecvError) -> Self { + match err { + RecvError::Disconnected => Self::Disconnected, + } + } +} + +/// An error that may be emitted when attempting to wait for a value on a receiver with a timeout +/// when the receive operation times out or all senders are dropped and there are no values left +/// in the channel. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RecvTimeoutError { + /// A timeout occurred when attempting to receive a message. + Timeout, + /// All senders were dropped and no messages are waiting in the channel, so no further messages can be received. + Disconnected, +} + +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RecvTimeoutError::Timeout => "timed out waiting on a channel".fmt(f), + RecvTimeoutError::Disconnected => "channel is empty and closed".fmt(f), + } + } +} + +impl std::error::Error for RecvTimeoutError {} + +impl From<RecvError> for RecvTimeoutError { + fn from(err: RecvError) -> Self { + match err { + RecvError::Disconnected => Self::Disconnected, + } + } +} + +enum TryRecvTimeoutError { + Empty, + Timeout, + Disconnected, +} + +// TODO: Investigate some sort of invalidation flag for timeouts +#[cfg(feature = "spin")] +struct Hook<T, S: ?Sized>(Option<Spinlock<Option<T>>>, S); + +#[cfg(not(feature = "spin"))] +struct Hook<T, S: ?Sized>(Option<Mutex<Option<T>>>, S); + +#[cfg(feature = "spin")] +impl<T, S: ?Sized + Signal> Hook<T, S> { + pub fn slot(msg: Option<T>, signal: S) -> Arc<Self> + where + S: Sized, + { + Arc::new(Self(Some(Spinlock::new(msg)), signal)) + } + + fn lock(&self) -> Option<SpinlockGuard<'_, Option<T>>> { + self.0.as_ref().map(|s| s.lock()) + } +} + +#[cfg(not(feature = "spin"))] +impl<T, S: ?Sized + Signal> Hook<T, S> { + pub fn slot(msg: Option<T>, signal: S) -> Arc<Self> + where + S: Sized, + { + Arc::new(Self(Some(Mutex::new(msg)), signal)) + } + + fn lock(&self) -> Option<MutexGuard<'_, Option<T>>> { + self.0.as_ref().map(|s| s.lock().unwrap()) + } +} + +impl<T, S: ?Sized + Signal> Hook<T, S> { + pub fn fire_recv(&self) -> (T, &S) { + let msg = self.lock().unwrap().take().unwrap(); + (msg, self.signal()) + } + + pub fn fire_send(&self, msg: T) -> (Option<T>, &S) { + let ret = match self.lock() { + Some(mut lock) => { + *lock = Some(msg); + None + } + None => Some(msg), + }; + (ret, self.signal()) + } + + pub fn is_empty(&self) -> bool { + self.lock().map(|s| s.is_none()).unwrap_or(true) + } + + pub fn try_take(&self) -> Option<T> { + self.lock().unwrap().take() + } + + pub fn trigger(signal: S) -> Arc<Self> + where + S: Sized, + { + Arc::new(Self(None, signal)) + } + + pub fn signal(&self) -> &S { + &self.1 + } + + pub fn fire_nothing(&self) -> bool { + self.signal().fire() + } +} + +impl<T> Hook<T, SyncSignal> { + pub fn wait_recv(&self, abort: &AtomicBool) -> Option<T> { + loop { + let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg + let msg = self.lock().unwrap().take(); + if let Some(msg) = msg { + break Some(msg); + } else if disconnected { + break None; + } else { + self.signal().wait() + } + } + } + + // Err(true) if timeout + pub fn wait_deadline_recv(&self, abort: &AtomicBool, deadline: Instant) -> Result<T, bool> { + loop { + let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg + let msg = self.lock().unwrap().take(); + if let Some(msg) = msg { + break Ok(msg); + } else if disconnected { + break Err(false); + } else if let Some(dur) = deadline.checked_duration_since(Instant::now()) { + self.signal().wait_timeout(dur); + } else { + break Err(true); + } + } + } + + pub fn wait_send(&self, abort: &AtomicBool) { + loop { + let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg + if disconnected || self.lock().unwrap().is_none() { + break; + } + + self.signal().wait(); + } + } + + // Err(true) if timeout + pub fn wait_deadline_send(&self, abort: &AtomicBool, deadline: Instant) -> Result<(), bool> { + loop { + let disconnected = abort.load(Ordering::SeqCst); // Check disconnect *before* msg + if self.lock().unwrap().is_none() { + break Ok(()); + } else if disconnected { + break Err(false); + } else if let Some(dur) = deadline.checked_duration_since(Instant::now()) { + self.signal().wait_timeout(dur); + } else { + break Err(true); + } + } + } +} + +#[cfg(feature = "spin")] +#[inline] +fn wait_lock<T>(lock: &Spinlock<T>) -> SpinlockGuard<T> { + let mut i = 4; + loop { + for _ in 0..10 { + if let Some(guard) = lock.try_lock() { + return guard; + } + thread::yield_now(); + } + // Sleep for at most ~1 ms + thread::sleep(Duration::from_nanos(1 << i.min(20))); + i += 1; + } +} + +#[cfg(not(feature = "spin"))] +#[inline] +fn wait_lock<'a, T>(lock: &'a Mutex<T>) -> MutexGuard<'a, T> { + lock.lock().unwrap() +} + +#[cfg(not(feature = "spin"))] +use std::sync::{Mutex, MutexGuard}; + +#[cfg(feature = "spin")] +type ChanLock<T> = Spinlock<T>; +#[cfg(not(feature = "spin"))] +type ChanLock<T> = Mutex<T>; + + +type SignalVec<T> = VecDeque<Arc<Hook<T, dyn signal::Signal>>>; +struct Chan<T> { + sending: Option<(usize, SignalVec<T>)>, + queue: VecDeque<T>, + waiting: SignalVec<T>, +} + +impl<T> Chan<T> { + fn pull_pending(&mut self, pull_extra: bool) { + if let Some((cap, sending)) = &mut self.sending { + let effective_cap = *cap + pull_extra as usize; + + while self.queue.len() < effective_cap { + if let Some(s) = sending.pop_front() { + let (msg, signal) = s.fire_recv(); + signal.fire(); + self.queue.push_back(msg); + } else { + break; + } + } + } + } + + fn try_wake_receiver_if_pending(&mut self) { + if !self.queue.is_empty() { + while Some(false) == self.waiting.pop_front().map(|s| s.fire_nothing()) {} + } + } +} + +struct Shared<T> { + chan: ChanLock<Chan<T>>, + disconnected: AtomicBool, + sender_count: AtomicUsize, + receiver_count: AtomicUsize, +} + +impl<T> Shared<T> { + fn new(cap: Option<usize>) -> Self { + Self { + chan: ChanLock::new(Chan { + sending: cap.map(|cap| (cap, VecDeque::new())), + queue: VecDeque::new(), + waiting: VecDeque::new(), + }), + disconnected: AtomicBool::new(false), + sender_count: AtomicUsize::new(1), + receiver_count: AtomicUsize::new(1), + } + } + + fn send<S: Signal, R: From<Result<(), TrySendTimeoutError<T>>>>( + &self, + msg: T, + should_block: bool, + make_signal: impl FnOnce(T) -> Arc<Hook<T, S>>, + do_block: impl FnOnce(Arc<Hook<T, S>>) -> R, + ) -> R { + let mut chan = wait_lock(&self.chan); + + if self.is_disconnected() { + Err(TrySendTimeoutError::Disconnected(msg)).into() + } else if !chan.waiting.is_empty() { + let mut msg = Some(msg); + + loop { + let slot = chan.waiting.pop_front(); + match slot.as_ref().map(|r| r.fire_send(msg.take().unwrap())) { + // No more waiting receivers and msg in queue, so break out of the loop + None if msg.is_none() => break, + // No more waiting receivers, so add msg to queue and break out of the loop + None => { + chan.queue.push_back(msg.unwrap()); + break; + } + Some((Some(m), signal)) => { + if signal.fire() { + // Was async and a stream, so didn't acquire the message. Wake another + // receiver, and do not yet push the message. + msg.replace(m); + continue; + } else { + // Was async and not a stream, so it did acquire the message. Push the + // message to the queue for it to be received. + chan.queue.push_back(m); + drop(chan); + break; + } + }, + Some((None, signal)) => { + drop(chan); + signal.fire(); + break; // Was sync, so it has acquired the message + }, + } + } + + Ok(()).into() + } else if chan.sending.as_ref().map(|(cap, _)| chan.queue.len() < *cap).unwrap_or(true) { + chan.queue.push_back(msg); + Ok(()).into() + } else if should_block { // Only bounded from here on + let hook = make_signal(msg); + chan.sending.as_mut().unwrap().1.push_back(hook.clone()); + drop(chan); + + do_block(hook) + } else { + Err(TrySendTimeoutError::Full(msg)).into() + } + } + + fn send_sync( + &self, + msg: T, + block: Option<Option<Instant>>, + ) -> Result<(), TrySendTimeoutError<T>> { + self.send( + // msg + msg, + // should_block + block.is_some(), + // make_signal + |msg| Hook::slot(Some(msg), SyncSignal::default()), + // do_block + |hook| if let Some(deadline) = block.unwrap() { + hook.wait_deadline_send(&self.disconnected, deadline) + .or_else(|timed_out| { + if timed_out { // Remove our signal + let hook: Arc<Hook<T, dyn signal::Signal>> = hook.clone(); + wait_lock(&self.chan).sending + .as_mut() + .unwrap().1 + .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); + } + hook.try_take().map(|msg| if self.is_disconnected() { + Err(TrySendTimeoutError::Disconnected(msg)) + } else { + Err(TrySendTimeoutError::Timeout(msg)) + }) + .unwrap_or(Ok(())) + }) + } else { + hook.wait_send(&self.disconnected); + + match hook.try_take() { + Some(msg) => Err(TrySendTimeoutError::Disconnected(msg)), + None => Ok(()), + } + }, + ) + } + + fn recv<S: Signal, R: From<Result<T, TryRecvTimeoutError>>>( + &self, + should_block: bool, + make_signal: impl FnOnce() -> Arc<Hook<T, S>>, + do_block: impl FnOnce(Arc<Hook<T, S>>) -> R, + ) -> R { + let mut chan = wait_lock(&self.chan); + chan.pull_pending(true); + + if let Some(msg) = chan.queue.pop_front() { + drop(chan); + Ok(msg).into() + } else if self.is_disconnected() { + drop(chan); + Err(TryRecvTimeoutError::Disconnected).into() + } else if should_block { + let hook = make_signal(); + chan.waiting.push_back(hook.clone()); + drop(chan); + + do_block(hook) + } else { + drop(chan); + Err(TryRecvTimeoutError::Empty).into() + } + } + + fn recv_sync(&self, block: Option<Option<Instant>>) -> Result<T, TryRecvTimeoutError> { + self.recv( + // should_block + block.is_some(), + // make_signal + || Hook::slot(None, SyncSignal::default()), + // do_block + |hook| if let Some(deadline) = block.unwrap() { + hook.wait_deadline_recv(&self.disconnected, deadline) + .or_else(|timed_out| { + if timed_out { // Remove our signal + let hook: Arc<Hook<T, dyn Signal>> = hook.clone(); + wait_lock(&self.chan).waiting + .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); + } + match hook.try_take() { + Some(msg) => Ok(msg), + None => { + let disconnected = self.is_disconnected(); // Check disconnect *before* msg + if let Some(msg) = wait_lock(&self.chan).queue.pop_front() { + Ok(msg) + } else if disconnected { + Err(TryRecvTimeoutError::Disconnected) + } else { + Err(TryRecvTimeoutError::Timeout) + } + }, + } + }) + } else { + hook.wait_recv(&self.disconnected) + .or_else(|| wait_lock(&self.chan).queue.pop_front()) + .ok_or(TryRecvTimeoutError::Disconnected) + }, + ) + } + + /// Disconnect anything listening on this channel (this will not prevent receivers receiving + /// msgs that have already been sent) + fn disconnect_all(&self) { + self.disconnected.store(true, Ordering::Relaxed); + + let mut chan = wait_lock(&self.chan); + chan.pull_pending(false); + if let Some((_, sending)) = chan.sending.as_ref() { + sending.iter().for_each(|hook| { + hook.signal().fire(); + }) + } + chan.waiting.iter().for_each(|hook| { + hook.signal().fire(); + }); + } + + fn is_disconnected(&self) -> bool { + self.disconnected.load(Ordering::SeqCst) + } + + fn is_empty(&self) -> bool { + self.len() == 0 + } + + fn is_full(&self) -> bool { + self.capacity().map(|cap| cap == self.len()).unwrap_or(false) + } + + fn len(&self) -> usize { + let mut chan = wait_lock(&self.chan); + chan.pull_pending(false); + chan.queue.len() + } + + fn capacity(&self) -> Option<usize> { + wait_lock(&self.chan).sending.as_ref().map(|(cap, _)| *cap) + } + + fn sender_count(&self) -> usize { + self.sender_count.load(Ordering::Relaxed) + } + + fn receiver_count(&self) -> usize { + self.receiver_count.load(Ordering::Relaxed) + } +} + +/// A transmitting end of a channel. +pub struct Sender<T> { + shared: Arc<Shared<T>>, +} + +impl<T> Sender<T> { + /// Attempt to send a value into the channel. If the channel is bounded and full, or all + /// receivers have been dropped, an error is returned. If the channel associated with this + /// sender is unbounded, this method has the same behaviour as [`Sender::send`]. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> { + self.shared.send_sync(msg, None).map_err(|err| match err { + TrySendTimeoutError::Full(msg) => TrySendError::Full(msg), + TrySendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg), + _ => unreachable!(), + }) + } + + /// Send a value into the channel, returning an error if all receivers have been dropped. + /// If the channel is bounded and is full, this method will block until space is available + /// or all receivers have been dropped. If the channel is unbounded, this method will not + /// block. + pub fn send(&self, msg: T) -> Result<(), SendError<T>> { + self.shared.send_sync(msg, Some(None)).map_err(|err| match err { + TrySendTimeoutError::Disconnected(msg) => SendError(msg), + _ => unreachable!(), + }) + } + + /// Send a value into the channel, returning an error if all receivers have been dropped + /// or the deadline has passed. If the channel is bounded and is full, this method will + /// block until space is available, the deadline is reached, or all receivers have been + /// dropped. + pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError<T>> { + self.shared.send_sync(msg, Some(Some(deadline))).map_err(|err| match err { + TrySendTimeoutError::Disconnected(msg) => SendTimeoutError::Disconnected(msg), + TrySendTimeoutError::Timeout(msg) => SendTimeoutError::Timeout(msg), + _ => unreachable!(), + }) + } + + /// Send a value into the channel, returning an error if all receivers have been dropped + /// or the timeout has expired. If the channel is bounded and is full, this method will + /// block until space is available, the timeout has expired, or all receivers have been + /// dropped. + pub fn send_timeout(&self, msg: T, dur: Duration) -> Result<(), SendTimeoutError<T>> { + self.send_deadline(msg, Instant::now().checked_add(dur).unwrap()) + } + + /// Returns true if all receivers for this channel have been dropped. + pub fn is_disconnected(&self) -> bool { + self.shared.is_disconnected() + } + + /// Returns true if the channel is empty. + /// Note: Zero-capacity channels are always empty. + pub fn is_empty(&self) -> bool { + self.shared.is_empty() + } + + /// Returns true if the channel is full. + /// Note: Zero-capacity channels are always full. + pub fn is_full(&self) -> bool { + self.shared.is_full() + } + + /// Returns the number of messages in the channel + pub fn len(&self) -> usize { + self.shared.len() + } + + /// If the channel is bounded, returns its capacity. + pub fn capacity(&self) -> Option<usize> { + self.shared.capacity() + } + + /// Get the number of senders that currently exist, including this one. + pub fn sender_count(&self) -> usize { + self.shared.sender_count() + } + + /// Get the number of receivers that currently exist. + /// + /// Note that this method makes no guarantees that a subsequent send will succeed; it's + /// possible that between `receiver_count()` being called and a `send()`, all open receivers + /// could drop. + pub fn receiver_count(&self) -> usize { + self.shared.receiver_count() + } + + /// Creates a [`WeakSender`] that does not keep the channel open. + /// + /// The channel is closed once all `Sender`s are dropped, even if there + /// are still active `WeakSender`s. + pub fn downgrade(&self) -> WeakSender<T> { + WeakSender { + shared: Arc::downgrade(&self.shared), + } + } + + /// Returns whether the senders are belong to the same channel. + pub fn same_channel(&self, other: &Sender<T>) -> bool { + Arc::ptr_eq(&self.shared, &other.shared) + } +} + +impl<T> Clone for Sender<T> { + /// Clone this sender. [`Sender`] acts as a handle to the ending a channel. Remaining channel + /// contents will only be cleaned up when all senders and the receiver have been dropped. + fn clone(&self) -> Self { + self.shared.sender_count.fetch_add(1, Ordering::Relaxed); + Self { shared: self.shared.clone() } + } +} + +impl<T> fmt::Debug for Sender<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Sender").finish() + } +} + +impl<T> Drop for Sender<T> { + fn drop(&mut self) { + // Notify receivers that all senders have been dropped if the number of senders drops to 0. + if self.shared.sender_count.fetch_sub(1, Ordering::Relaxed) == 1 { + self.shared.disconnect_all(); + } + } +} + +/// A sender that does not prevent the channel from being closed. +/// +/// Weak senders do not count towards the number of active senders on the channel. As soon as +/// all normal [`Sender`]s are dropped, the channel is closed, even if there is still a +/// `WeakSender`. +/// +/// To send messages, a `WeakSender` must first be upgraded to a `Sender` using the [`upgrade`] +/// method. +pub struct WeakSender<T> { + shared: Weak<Shared<T>>, +} + +impl<T> WeakSender<T> { + /// Tries to upgrade the `WeakSender` to a [`Sender`], in order to send messages. + /// + /// Returns `None` if the channel was closed already. Note that a `Some` return value + /// does not guarantee that the channel is still open. + pub fn upgrade(&self) -> Option<Sender<T>> { + self.shared + .upgrade() + // check that there are still live senders + .filter(|shared| { + shared + .sender_count + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count| { + if count == 0 { + // all senders are closed already -> don't increase the sender count + None + } else { + // there is still at least one active sender + Some(count + 1) + } + }) + .is_ok() + }) + .map(|shared| Sender { shared }) + } +} + +/// The receiving end of a channel. +/// +/// Note: Cloning the receiver *does not* turn this channel into a broadcast channel. +/// Each message will only be received by a single receiver. This is useful for +/// implementing work stealing for concurrent programs. +pub struct Receiver<T> { + shared: Arc<Shared<T>>, +} + +impl<T> Receiver<T> { + /// Attempt to fetch an incoming value from the channel associated with this receiver, + /// returning an error if the channel is empty or if all senders have been dropped. + pub fn try_recv(&self) -> Result<T, TryRecvError> { + self.shared.recv_sync(None).map_err(|err| match err { + TryRecvTimeoutError::Disconnected => TryRecvError::Disconnected, + TryRecvTimeoutError::Empty => TryRecvError::Empty, + _ => unreachable!(), + }) + } + + /// Wait for an incoming value from the channel associated with this receiver, returning an + /// error if all senders have been dropped. + pub fn recv(&self) -> Result<T, RecvError> { + self.shared.recv_sync(Some(None)).map_err(|err| match err { + TryRecvTimeoutError::Disconnected => RecvError::Disconnected, + _ => unreachable!(), + }) + } + + /// Wait for an incoming value from the channel associated with this receiver, returning an + /// error if all senders have been dropped or the deadline has passed. + pub fn recv_deadline(&self, deadline: Instant) -> Result<T, RecvTimeoutError> { + self.shared.recv_sync(Some(Some(deadline))).map_err(|err| match err { + TryRecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + TryRecvTimeoutError::Timeout => RecvTimeoutError::Timeout, + _ => unreachable!(), + }) + } + + /// Wait for an incoming value from the channel associated with this receiver, returning an + /// error if all senders have been dropped or the timeout has expired. + pub fn recv_timeout(&self, dur: Duration) -> Result<T, RecvTimeoutError> { + self.recv_deadline(Instant::now().checked_add(dur).unwrap()) + } + + /// Create a blocking iterator over the values received on the channel that finishes iteration + /// when all senders have been dropped. + /// + /// You can also create a self-owned iterator with [`Receiver::into_iter`]. + pub fn iter(&self) -> Iter<T> { + Iter { receiver: &self } + } + + /// A non-blocking iterator over the values received on the channel that finishes iteration + /// when all senders have been dropped or the channel is empty. + pub fn try_iter(&self) -> TryIter<T> { + TryIter { receiver: &self } + } + + /// Take all msgs currently sitting in the channel and produce an iterator over them. Unlike + /// `try_iter`, the iterator will not attempt to fetch any more values from the channel once + /// the function has been called. + pub fn drain(&self) -> Drain<T> { + let mut chan = wait_lock(&self.shared.chan); + chan.pull_pending(false); + let queue = std::mem::take(&mut chan.queue); + + Drain { queue, _phantom: PhantomData } + } + + /// Returns true if all senders for this channel have been dropped. + pub fn is_disconnected(&self) -> bool { + self.shared.is_disconnected() + } + + /// Returns true if the channel is empty. + /// Note: Zero-capacity channels are always empty. + pub fn is_empty(&self) -> bool { + self.shared.is_empty() + } + + /// Returns true if the channel is full. + /// Note: Zero-capacity channels are always full. + pub fn is_full(&self) -> bool { + self.shared.is_full() + } + + /// Returns the number of messages in the channel. + pub fn len(&self) -> usize { + self.shared.len() + } + + /// If the channel is bounded, returns its capacity. + pub fn capacity(&self) -> Option<usize> { + self.shared.capacity() + } + + /// Get the number of senders that currently exist. + pub fn sender_count(&self) -> usize { + self.shared.sender_count() + } + + /// Get the number of receivers that currently exist, including this one. + pub fn receiver_count(&self) -> usize { + self.shared.receiver_count() + } + + /// Returns whether the receivers are belong to the same channel. + pub fn same_channel(&self, other: &Receiver<T>) -> bool { + Arc::ptr_eq(&self.shared, &other.shared) + } +} + +impl<T> Clone for Receiver<T> { + /// Clone this receiver. [`Receiver`] acts as a handle to the ending a channel. Remaining + /// channel contents will only be cleaned up when all senders and the receiver have been + /// dropped. + /// + /// Note: Cloning the receiver *does not* turn this channel into a broadcast channel. + /// Each message will only be received by a single receiver. This is useful for + /// implementing work stealing for concurrent programs. + fn clone(&self) -> Self { + self.shared.receiver_count.fetch_add(1, Ordering::Relaxed); + Self { shared: self.shared.clone() } + } +} + +impl<T> fmt::Debug for Receiver<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Receiver").finish() + } +} + +impl<T> Drop for Receiver<T> { + fn drop(&mut self) { + // Notify senders that all receivers have been dropped if the number of receivers drops + // to 0. + if self.shared.receiver_count.fetch_sub(1, Ordering::Relaxed) == 1 { + self.shared.disconnect_all(); + } + } +} + +/// This exists as a shorthand for [`Receiver::iter`]. +impl<'a, T> IntoIterator for &'a Receiver<T> { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + Iter { receiver: self } + } +} + +impl<T> IntoIterator for Receiver<T> { + type Item = T; + type IntoIter = IntoIter<T>; + + /// Creates a self-owned but semantically equivalent alternative to [`Receiver::iter`]. + fn into_iter(self) -> Self::IntoIter { + IntoIter { receiver: self } + } +} + +/// An iterator over the msgs received from a channel. +pub struct Iter<'a, T> { + receiver: &'a Receiver<T>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + self.receiver.recv().ok() + } +} + +/// An non-blocking iterator over the msgs received from a channel. +pub struct TryIter<'a, T> { + receiver: &'a Receiver<T>, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + self.receiver.try_recv().ok() + } +} + +/// An fixed-sized iterator over the msgs drained from a channel. +#[derive(Debug)] +pub struct Drain<'a, T> { + queue: VecDeque<T>, + /// A phantom field used to constrain the lifetime of this iterator. We do this because the + /// implementation may change and we don't want to unintentionally constrain it. Removing this + /// lifetime later is a possibility. + _phantom: PhantomData<&'a ()>, +} + +impl<'a, T> Iterator for Drain<'a, T> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + self.queue.pop_front() + } +} + +impl<'a, T> ExactSizeIterator for Drain<'a, T> { + fn len(&self) -> usize { + self.queue.len() + } +} + +/// An owned iterator over the msgs received from a channel. +pub struct IntoIter<T> { + receiver: Receiver<T>, +} + +impl<T> Iterator for IntoIter<T> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + self.receiver.recv().ok() + } +} + +/// Create a channel with no maximum capacity. +/// +/// Create an unbounded channel with a [`Sender`] and [`Receiver`] connected to each end respectively. Values sent in +/// one end of the channel will be received on the other end. The channel is thread-safe, and both [`Sender`] and +/// [`Receiver`] may be sent to or shared between threads as necessary. In addition, both [`Sender`] and [`Receiver`] +/// may be cloned. +/// +/// # Examples +/// ``` +/// let (tx, rx) = flume::unbounded(); +/// +/// tx.send(42).unwrap(); +/// assert_eq!(rx.recv().unwrap(), 42); +/// ``` +pub fn unbounded<T>() -> (Sender<T>, Receiver<T>) { + let shared = Arc::new(Shared::new(None)); + ( + Sender { shared: shared.clone() }, + Receiver { shared }, + ) +} + +/// Create a channel with a maximum capacity. +/// +/// Create a bounded channel with a [`Sender`] and [`Receiver`] connected to each end respectively. Values sent in one +/// end of the channel will be received on the other end. The channel is thread-safe, and both [`Sender`] and +/// [`Receiver`] may be sent to or shared between threads as necessary. In addition, both [`Sender`] and [`Receiver`] +/// may be cloned. +/// +/// Unlike an [`unbounded`] channel, if there is no space left for new messages, calls to +/// [`Sender::send`] will block (unblocking once a receiver has made space). If blocking behaviour +/// is not desired, [`Sender::try_send`] may be used. +/// +/// Like `std::sync::mpsc`, `flume` supports 'rendezvous' channels. A bounded queue with a maximum capacity of zero +/// will block senders until a receiver is available to take the value. You can imagine a rendezvous channel as a +/// ['Glienicke Bridge'](https://en.wikipedia.org/wiki/Glienicke_Bridge)-style location at which senders and receivers +/// perform a handshake and transfer ownership of a value. +/// +/// # Examples +/// ``` +/// let (tx, rx) = flume::bounded(32); +/// +/// for i in 1..33 { +/// tx.send(i).unwrap(); +/// } +/// assert!(tx.try_send(33).is_err()); +/// +/// assert_eq!(rx.try_iter().sum::<u32>(), (1..33).sum()); +/// ``` +pub fn bounded<T>(cap: usize) -> (Sender<T>, Receiver<T>) { + let shared = Arc::new(Shared::new(Some(cap))); + ( + Sender { shared: shared.clone() }, + Receiver { shared }, + ) +} diff --git a/vendor/flume/src/select.rs b/vendor/flume/src/select.rs new file mode 100644 index 0000000..cef15aa --- /dev/null +++ b/vendor/flume/src/select.rs @@ -0,0 +1,405 @@ +//! Types that permit waiting upon multiple blocking operations using the [`Selector`] interface. + +use crate::*; +use spin1::Mutex as Spinlock; +use std::{any::Any, marker::PhantomData}; + +#[cfg(feature = "eventual-fairness")] +use nanorand::Rng; + +// A unique token corresponding to an event in a selector +type Token = usize; + +struct SelectSignal( + thread::Thread, + Token, + AtomicBool, + Arc<Spinlock<VecDeque<Token>>>, +); + +impl Signal for SelectSignal { + fn fire(&self) -> bool { + self.2.store(true, Ordering::SeqCst); + self.3.lock().push_back(self.1); + self.0.unpark(); + false + } + + fn as_any(&self) -> &(dyn Any + 'static) { + self + } + fn as_ptr(&self) -> *const () { + self as *const _ as *const () + } +} + +trait Selection<'a, T> { + fn init(&mut self) -> Option<T>; + fn poll(&mut self) -> Option<T>; + fn deinit(&mut self); +} + +/// An error that may be emitted when attempting to wait for a value on a receiver. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SelectError { + /// A timeout occurred when waiting on a `Selector`. + Timeout, +} + +impl fmt::Display for SelectError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SelectError::Timeout => "timeout occurred".fmt(f), + } + } +} + +impl std::error::Error for SelectError {} + +/// A type used to wait upon multiple blocking operations at once. +/// +/// A [`Selector`] implements [`select`](https://en.wikipedia.org/wiki/Select_(Unix))-like behaviour, +/// allowing a thread to wait upon the result of more than one operation at once. +/// +/// # Examples +/// ``` +/// let (tx0, rx0) = flume::unbounded(); +/// let (tx1, rx1) = flume::unbounded(); +/// +/// std::thread::spawn(move || { +/// tx0.send(true).unwrap(); +/// tx1.send(42).unwrap(); +/// }); +/// +/// flume::Selector::new() +/// .recv(&rx0, |b| println!("Received {:?}", b)) +/// .recv(&rx1, |n| println!("Received {:?}", n)) +/// .wait(); +/// ``` +pub struct Selector<'a, T: 'a> { + selections: Vec<Box<dyn Selection<'a, T> + 'a>>, + next_poll: usize, + signalled: Arc<Spinlock<VecDeque<Token>>>, + #[cfg(feature = "eventual-fairness")] + rng: nanorand::WyRand, + phantom: PhantomData<*const ()>, +} + +impl<'a, T: 'a> Default for Selector<'a, T> { + fn default() -> Self { + Self::new() + } +} + +impl<'a, T: 'a> fmt::Debug for Selector<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Selector").finish() + } +} + +impl<'a, T> Selector<'a, T> { + /// Create a new selector. + pub fn new() -> Self { + Self { + selections: Vec::new(), + next_poll: 0, + signalled: Arc::default(), + phantom: PhantomData::default(), + #[cfg(feature = "eventual-fairness")] + rng: nanorand::WyRand::new(), + } + } + + /// Add a send operation to the selector that sends the provided value. + /// + /// Once added, the selector can be used to run the provided handler function on completion of this operation. + pub fn send<U, F: FnMut(Result<(), SendError<U>>) -> T + 'a>( + mut self, + sender: &'a Sender<U>, + msg: U, + mapper: F, + ) -> Self { + struct SendSelection<'a, T, F, U> { + sender: &'a Sender<U>, + msg: Option<U>, + token: Token, + signalled: Arc<Spinlock<VecDeque<Token>>>, + hook: Option<Arc<Hook<U, SelectSignal>>>, + mapper: F, + phantom: PhantomData<T>, + } + + impl<'a, T, F, U> Selection<'a, T> for SendSelection<'a, T, F, U> + where + F: FnMut(Result<(), SendError<U>>) -> T, + { + fn init(&mut self) -> Option<T> { + let token = self.token; + let signalled = self.signalled.clone(); + let r = self.sender.shared.send( + self.msg.take().unwrap(), + true, + |msg| { + Hook::slot( + Some(msg), + SelectSignal( + thread::current(), + token, + AtomicBool::new(false), + signalled, + ), + ) + }, + // Always runs + |h| { + self.hook = Some(h); + Ok(()) + }, + ); + + if self.hook.is_none() { + Some((self.mapper)(match r { + Ok(()) => Ok(()), + Err(TrySendTimeoutError::Disconnected(msg)) => Err(SendError(msg)), + _ => unreachable!(), + })) + } else { + None + } + } + + fn poll(&mut self) -> Option<T> { + let res = if self.sender.shared.is_disconnected() { + // Check the hook one last time + if let Some(msg) = self.hook.as_ref()?.try_take() { + Err(SendError(msg)) + } else { + Ok(()) + } + } else if self.hook.as_ref().unwrap().is_empty() { + // The message was sent + Ok(()) + } else { + return None; + }; + + Some((&mut self.mapper)(res)) + } + + fn deinit(&mut self) { + if let Some(hook) = self.hook.take() { + // Remove hook + let hook: Arc<Hook<U, dyn Signal>> = hook; + wait_lock(&self.sender.shared.chan) + .sending + .as_mut() + .unwrap() + .1 + .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); + } + } + } + + let token = self.selections.len(); + self.selections.push(Box::new(SendSelection { + sender, + msg: Some(msg), + token, + signalled: self.signalled.clone(), + hook: None, + mapper, + phantom: Default::default(), + })); + + self + } + + /// Add a receive operation to the selector. + /// + /// Once added, the selector can be used to run the provided handler function on completion of this operation. + pub fn recv<U, F: FnMut(Result<U, RecvError>) -> T + 'a>( + mut self, + receiver: &'a Receiver<U>, + mapper: F, + ) -> Self { + struct RecvSelection<'a, T, F, U> { + receiver: &'a Receiver<U>, + token: Token, + signalled: Arc<Spinlock<VecDeque<Token>>>, + hook: Option<Arc<Hook<U, SelectSignal>>>, + mapper: F, + received: bool, + phantom: PhantomData<T>, + } + + impl<'a, T, F, U> Selection<'a, T> for RecvSelection<'a, T, F, U> + where + F: FnMut(Result<U, RecvError>) -> T, + { + fn init(&mut self) -> Option<T> { + let token = self.token; + let signalled = self.signalled.clone(); + let r = self.receiver.shared.recv( + true, + || { + Hook::trigger(SelectSignal( + thread::current(), + token, + AtomicBool::new(false), + signalled, + )) + }, + // Always runs + |h| { + self.hook = Some(h); + Err(TryRecvTimeoutError::Timeout) + }, + ); + + if self.hook.is_none() { + Some((self.mapper)(match r { + Ok(msg) => Ok(msg), + Err(TryRecvTimeoutError::Disconnected) => Err(RecvError::Disconnected), + _ => unreachable!(), + })) + } else { + None + } + } + + fn poll(&mut self) -> Option<T> { + let res = if let Ok(msg) = self.receiver.try_recv() { + self.received = true; + Ok(msg) + } else if self.receiver.shared.is_disconnected() { + Err(RecvError::Disconnected) + } else { + return None; + }; + + Some((&mut self.mapper)(res)) + } + + fn deinit(&mut self) { + if let Some(hook) = self.hook.take() { + // Remove hook + let hook: Arc<Hook<U, dyn Signal>> = hook; + wait_lock(&self.receiver.shared.chan) + .waiting + .retain(|s| s.signal().as_ptr() != hook.signal().as_ptr()); + // If we were woken, but never polled, wake up another + if !self.received + && hook + .signal() + .as_any() + .downcast_ref::<SelectSignal>() + .unwrap() + .2 + .load(Ordering::SeqCst) + { + wait_lock(&self.receiver.shared.chan).try_wake_receiver_if_pending(); + } + } + } + } + + let token = self.selections.len(); + self.selections.push(Box::new(RecvSelection { + receiver, + token, + signalled: self.signalled.clone(), + hook: None, + mapper, + received: false, + phantom: Default::default(), + })); + + self + } + + fn wait_inner(mut self, deadline: Option<Instant>) -> Option<T> { + #[cfg(feature = "eventual-fairness")] + { + self.next_poll = self.rng.generate_range(0..self.selections.len()); + } + + let res = 'outer: loop { + // Init signals + for _ in 0..self.selections.len() { + if let Some(val) = self.selections[self.next_poll].init() { + break 'outer Some(val); + } + self.next_poll = (self.next_poll + 1) % self.selections.len(); + } + + // Speculatively poll + if let Some(msg) = self.poll() { + break 'outer Some(msg); + } + + loop { + if let Some(deadline) = deadline { + if let Some(dur) = deadline.checked_duration_since(Instant::now()) { + thread::park_timeout(dur); + } + } else { + thread::park(); + } + + if deadline.map(|d| Instant::now() >= d).unwrap_or(false) { + break 'outer self.poll(); + } + + let token = if let Some(token) = self.signalled.lock().pop_front() { + token + } else { + // Spurious wakeup, park again + continue; + }; + + // Attempt to receive a message + if let Some(msg) = self.selections[token].poll() { + break 'outer Some(msg); + } + } + }; + + // Deinit signals + for s in &mut self.selections { + s.deinit(); + } + + res + } + + fn poll(&mut self) -> Option<T> { + for _ in 0..self.selections.len() { + if let Some(val) = self.selections[self.next_poll].poll() { + return Some(val); + } + self.next_poll = (self.next_poll + 1) % self.selections.len(); + } + None + } + + /// Wait until one of the events associated with this [`Selector`] has completed. If the `eventual-fairness` + /// feature flag is enabled, this method is fair and will handle a random event of those that are ready. + pub fn wait(self) -> T { + self.wait_inner(None).unwrap() + } + + /// Wait until one of the events associated with this [`Selector`] has completed or the timeout has expired. If the + /// `eventual-fairness` feature flag is enabled, this method is fair and will handle a random event of those that + /// are ready. + pub fn wait_timeout(self, dur: Duration) -> Result<T, SelectError> { + self.wait_inner(Some(Instant::now() + dur)) + .ok_or(SelectError::Timeout) + } + + /// Wait until one of the events associated with this [`Selector`] has completed or the deadline has been reached. + /// If the `eventual-fairness` feature flag is enabled, this method is fair and will handle a random event of those + /// that are ready. + pub fn wait_deadline(self, deadline: Instant) -> Result<T, SelectError> { + self.wait_inner(Some(deadline)).ok_or(SelectError::Timeout) + } +} diff --git a/vendor/flume/src/signal.rs b/vendor/flume/src/signal.rs new file mode 100644 index 0000000..89395a3 --- /dev/null +++ b/vendor/flume/src/signal.rs @@ -0,0 +1,33 @@ +use std::{thread::{self, Thread}, time::Duration, any::Any}; + +pub trait Signal: Send + Sync + 'static { + /// Fire the signal, returning whether it is a stream signal. This is because streams do not + /// acquire a message when woken, so signals must be fired until one that does acquire a message + /// is fired, otherwise a wakeup could be missed, leading to a lost message until one is eagerly + /// grabbed by a receiver. + fn fire(&self) -> bool; + fn as_any(&self) -> &(dyn Any + 'static); + fn as_ptr(&self) -> *const (); +} + +pub struct SyncSignal(Thread); + +impl Default for SyncSignal { + fn default() -> Self { + Self(thread::current()) + } +} + +impl Signal for SyncSignal { + fn fire(&self) -> bool { + self.0.unpark(); + false + } + fn as_any(&self) -> &(dyn Any + 'static) { self } + fn as_ptr(&self) -> *const () { self as *const _ as *const () } +} + +impl SyncSignal { + pub fn wait(&self) { thread::park(); } + pub fn wait_timeout(&self, dur: Duration) { thread::park_timeout(dur); } +} diff --git a/vendor/flume/tests/after.rs b/vendor/flume/tests/after.rs new file mode 100644 index 0000000..6d25108 --- /dev/null +++ b/vendor/flume/tests/after.rs @@ -0,0 +1,339 @@ +// //! Tests for the after channel flavor. + +// #[macro_use] +// extern crate crossbeam_channel; +// extern crate crossbeam_utils; +// extern crate rand; + +// use std::sync::atomic::AtomicUsize; +// use std::sync::atomic::Ordering; +// use std::thread; +// use std::time::{Duration, Instant}; + +// use crossbeam_channel::{after, 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::<Vec<_>>(); +// 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::<Vec<_>>(); +// 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/vendor/flume/tests/array.rs b/vendor/flume/tests/array.rs new file mode 100644 index 0000000..a72bbe3 --- /dev/null +++ b/vendor/flume/tests/array.rs @@ -0,0 +1,657 @@ +//! Tests for the array channel flavor. + +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use flume::{bounded, Receiver}; +use flume::{RecvError, RecvTimeoutError, TryRecvError}; +use flume::{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!(r.recv().is_err()); + }); + 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::<i32>(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!(r.recv().is_err()); +} + +#[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!(r.recv().is_err()); + }); + 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!(r.recv().is_err()); + }); + 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::<usize>(3); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>(); + + 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::<DropCounter>(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<dyn Any + Send>; + + let (s, r) = bounded::<T>(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::<Option<Receiver<T>>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/flume/tests/async.rs b/vendor/flume/tests/async.rs new file mode 100644 index 0000000..6c2c7f2 --- /dev/null +++ b/vendor/flume/tests/async.rs @@ -0,0 +1,276 @@ +#[cfg(feature = "async")] +use { + flume::*, + futures::{stream::FuturesUnordered, StreamExt, TryFutureExt, Future}, + futures::task::{Context, Waker, Poll}, + async_std::prelude::FutureExt, + std::{time::Duration, sync::{atomic::{AtomicUsize, Ordering}, Arc}}, +}; + +#[cfg(feature = "async")] +#[test] +fn r#async_recv() { + let (tx, rx) = unbounded(); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + tx.send(42u32).unwrap(); + }); + + async_std::task::block_on(async { + assert_eq!(rx.recv_async().await.unwrap(), 42); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn r#async_send() { + let (tx, rx) = bounded(1); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + assert_eq!(rx.recv(), Ok(42)); + }); + + async_std::task::block_on(async { + tx.send_async(42u32).await.unwrap(); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn r#async_recv_disconnect() { + let (tx, rx) = bounded::<i32>(0); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + drop(tx) + }); + + async_std::task::block_on(async { + assert_eq!(rx.recv_async().await, Err(RecvError::Disconnected)); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn r#async_send_disconnect() { + let (tx, rx) = bounded(0); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + drop(rx) + }); + + async_std::task::block_on(async { + assert_eq!(tx.send_async(42u32).await, Err(SendError(42))); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn r#async_recv_drop_recv() { + let (tx, rx) = bounded::<i32>(10); + + let recv_fut = rx.recv_async(); + + async_std::task::block_on(async { + let res = async_std::future::timeout(std::time::Duration::from_millis(500), rx.recv_async()).await; + assert!(res.is_err()); + }); + + let rx2 = rx.clone(); + let t = std::thread::spawn(move || { + async_std::task::block_on(async { + rx2.recv_async().await + }) + }); + + std::thread::sleep(std::time::Duration::from_millis(500)); + + tx.send(42).unwrap(); + + drop(recv_fut); + + assert_eq!(t.join().unwrap(), Ok(42)) +} + +#[cfg(feature = "async")] +#[async_std::test] +async fn r#async_send_1_million_no_drop_or_reorder() { + #[derive(Debug)] + enum Message { + Increment { + old: u64, + }, + ReturnCount, + } + + let (tx, rx) = unbounded(); + + let t = async_std::task::spawn(async move { + let mut count = 0u64; + + while let Ok(Message::Increment { old }) = rx.recv_async().await { + assert_eq!(old, count); + count += 1; + } + + count + }); + + for next in 0..1_000_000 { + tx.send(Message::Increment { old: next }).unwrap(); + } + + tx.send(Message::ReturnCount).unwrap(); + + let count = t.await; + assert_eq!(count, 1_000_000) +} + +#[cfg(feature = "async")] +#[async_std::test] +async fn parallel_async_receivers() { + let (tx, rx) = flume::unbounded(); + let send_fut = async move { + let n_sends: usize = 100000; + for _ in 0..n_sends { + tx.send_async(()).await.unwrap(); + } + }; + + async_std::task::spawn( + send_fut + .timeout(Duration::from_secs(5)) + .map_err(|_| panic!("Send timed out!")) + ); + + let mut futures_unordered = (0..250) + .map(|_| async { + while let Ok(()) = rx.recv_async().await + /* rx.recv() is OK */ + {} + }) + .collect::<FuturesUnordered<_>>(); + + let recv_fut = async { + while futures_unordered.next().await.is_some() {} + }; + + recv_fut + .timeout(Duration::from_secs(5)) + .map_err(|_| panic!("Receive timed out!")) + .await + .unwrap(); + + println!("recv end"); +} + +#[cfg(feature = "async")] +#[test] +fn change_waker() { + let (tx, rx) = flume::bounded(1); + tx.send(()).unwrap(); + + struct DebugWaker(Arc<AtomicUsize>, Waker); + + impl DebugWaker { + fn new() -> Self { + let woken = Arc::new(AtomicUsize::new(0)); + let woken_cloned = woken.clone(); + let waker = waker_fn::waker_fn(move || { + woken.fetch_add(1, Ordering::SeqCst); + }); + DebugWaker(woken_cloned, waker) + } + + fn woken(&self) -> usize { + self.0.load(Ordering::SeqCst) + } + + fn ctx(&self) -> Context { + Context::from_waker(&self.1) + } + } + + // Check that the waker is correctly updated when sending tasks change their wakers + { + let send_fut = tx.send_async(()); + futures::pin_mut!(send_fut); + + let (waker1, waker2) = (DebugWaker::new(), DebugWaker::new()); + + // Set the waker to waker1 + assert_eq!(send_fut.as_mut().poll(&mut waker1.ctx()), Poll::Pending); + + // Change the waker to waker2 + assert_eq!(send_fut.poll(&mut waker2.ctx()), Poll::Pending); + + // Wake the future + rx.recv().unwrap(); + + // Check that waker2 was woken and waker1 was not + assert_eq!(waker1.woken(), 0); + assert_eq!(waker2.woken(), 1); + } + + // Check that the waker is correctly updated when receiving tasks change their wakers + { + rx.recv().unwrap(); + let recv_fut = rx.recv_async(); + futures::pin_mut!(recv_fut); + + let (waker1, waker2) = (DebugWaker::new(), DebugWaker::new()); + + // Set the waker to waker1 + assert_eq!(recv_fut.as_mut().poll(&mut waker1.ctx()), Poll::Pending); + + // Change the waker to waker2 + assert_eq!(recv_fut.poll(&mut waker2.ctx()), Poll::Pending); + + // Wake the future + tx.send(()).unwrap(); + + // Check that waker2 was woken and waker1 was not + assert_eq!(waker1.woken(), 0); + assert_eq!(waker2.woken(), 1); + } +} + +#[cfg(feature = "async")] +#[test] +fn spsc_single_threaded_value_ordering() { + async fn test() { + let (tx, rx) = flume::bounded(4); + tokio::select! { + _ = producer(tx) => {}, + _ = consumer(rx) => {}, + } + } + + async fn producer(tx: flume::Sender<usize>) { + for i in 0..100 { + tx.send_async(i).await.unwrap(); + } + } + + async fn consumer(rx: flume::Receiver<usize>) { + let mut expected = 0; + while let Ok(value) = rx.recv_async().await { + assert_eq!(value, expected); + expected += 1; + } + } + + let rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); + rt.block_on(test()); +} diff --git a/vendor/flume/tests/basic.rs b/vendor/flume/tests/basic.rs new file mode 100644 index 0000000..b937436 --- /dev/null +++ b/vendor/flume/tests/basic.rs @@ -0,0 +1,428 @@ +use std::time::{Instant, Duration}; +use flume::*; + +#[test] +fn send_recv() { + let (tx, rx) = unbounded(); + for i in 0..1000 { tx.send(i).unwrap(); } + for i in 0..1000 { assert_eq!(rx.try_recv().unwrap(), i); } + assert!(rx.try_recv().is_err()); +} + +#[test] +fn iter() { + let (tx, rx) = unbounded(); + for i in 0..1000 { tx.send(i).unwrap(); } + drop(tx); + assert_eq!(rx.iter().sum::<u32>(), (0..1000).sum()); +} + +#[test] +fn try_iter() { + let (tx, rx) = unbounded(); + for i in 0..1000 { tx.send(i).unwrap(); } + assert_eq!(rx.try_iter().sum::<u32>(), (0..1000).sum()); +} + +#[test] +fn iter_threaded() { + let (tx, rx) = unbounded(); + for i in 0..1000 { + let tx = tx.clone(); + std::thread::spawn(move || tx.send(i).unwrap()); + } + drop(tx); + assert_eq!(rx.iter().sum::<u32>(), (0..1000).sum()); +} + +#[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41 +#[test] +fn send_timeout() { + let dur = Duration::from_millis(350); + let max_error = Duration::from_millis(5); + let dur_min = dur.checked_sub(max_error).unwrap(); + let dur_max = dur.checked_add(max_error).unwrap(); + + let (tx, rx) = bounded(1); + + assert!(tx.send_timeout(42, dur).is_ok()); + + let then = Instant::now(); + assert!(tx.send_timeout(43, dur).is_err()); + let now = Instant::now(); + + let this = now.duration_since(then); + if !(dur_min < this && this < dur_max) { + panic!("timeout exceeded: {:?}", this); + } + + assert_eq!(rx.drain().count(), 1); + + drop(rx); + + assert!(tx.send_timeout(42, Duration::from_millis(350)).is_err()); +} + +#[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41 +#[test] +fn recv_timeout() { + let dur = Duration::from_millis(350); + let max_error = Duration::from_millis(5); + let dur_min = dur.checked_sub(max_error).unwrap(); + let dur_max = dur.checked_add(max_error).unwrap(); + + let (tx, rx) = unbounded(); + let then = Instant::now(); + assert!(rx.recv_timeout(dur).is_err()); + let now = Instant::now(); + + let this = now.duration_since(then); + if !(dur_min < this && this < dur_max) { + panic!("timeout exceeded: {:?}", this); + } + + tx.send(42).unwrap(); + assert_eq!(rx.recv_timeout(dur), Ok(42)); + assert!(Instant::now().duration_since(now) < max_error); +} + +#[cfg_attr(any(target_os = "macos", windows), ignore)] // FIXME #41 +#[test] +fn recv_deadline() { + let dur = Duration::from_millis(350); + let max_error = Duration::from_millis(5); + let dur_min = dur.checked_sub(max_error).unwrap(); + let dur_max = dur.checked_add(max_error).unwrap(); + + let (tx, rx) = unbounded(); + let then = Instant::now(); + assert!(rx.recv_deadline(then.checked_add(dur).unwrap()).is_err()); + let now = Instant::now(); + + let this = now.duration_since(then); + if !(dur_min < this && this < dur_max) { + panic!("timeout exceeded: {:?}", this); + } + + tx.send(42).unwrap(); + assert_eq!(rx.recv_deadline(now.checked_add(dur).unwrap()), Ok(42)); + assert!(Instant::now().duration_since(now) < max_error); +} + +#[test] +fn recv_timeout_missed_send() { + let (tx, rx) = bounded(10); + + assert!(rx.recv_timeout(Duration::from_millis(100)).is_err()); + + tx.send(42).unwrap(); + + assert_eq!(rx.recv(), Ok(42)); +} + +#[test] +fn disconnect_tx() { + let (tx, rx) = unbounded::<()>(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn disconnect_rx() { + let (tx, rx) = unbounded(); + drop(rx); + assert!(tx.send(0).is_err()); +} + +#[test] +fn drain() { + let (tx, rx) = unbounded(); + + for i in 0..100 { + tx.send(i).unwrap(); + } + + assert_eq!(rx.drain().sum::<u32>(), (0..100).sum()); + + for i in 0..100 { + tx.send(i).unwrap(); + } + + for i in 0..100 { + tx.send(i).unwrap(); + } + + rx.recv().unwrap(); + + (1u32..100).chain(0..100).zip(rx).for_each(|(l, r)| assert_eq!(l, r)); +} + +#[test] +fn try_send() { + let (tx, rx) = bounded(5); + + for i in 0..5 { + tx.try_send(i).unwrap(); + } + + assert!(tx.try_send(42).is_err()); + + assert_eq!(rx.recv(), Ok(0)); + + assert_eq!(tx.try_send(42), Ok(())); + + assert_eq!(rx.recv(), Ok(1)); + drop(rx); + + assert!(tx.try_send(42).is_err()); +} + +#[test] +fn send_bounded() { + let (tx, rx) = bounded(5); + + for _ in 0..5 { + tx.send(42).unwrap(); + } + + let _ = rx.recv().unwrap(); + + tx.send(42).unwrap(); + + assert!(tx.try_send(42).is_err()); + + rx.drain(); + + let mut ts = Vec::new(); + for _ in 0..100 { + let tx = tx.clone(); + ts.push(std::thread::spawn(move || { + for i in 0..10000 { + tx.send(i).unwrap(); + } + })); + } + + drop(tx); + + assert_eq!(rx.iter().sum::<u64>(), (0..10000).sum::<u64>() * 100); + + for t in ts { + t.join().unwrap(); + } + + assert!(rx.recv().is_err()); +} + +#[test] +fn rendezvous() { + let (tx, rx) = bounded(0); + + for i in 0..5 { + let tx = tx.clone(); + let t = std::thread::spawn(move || { + assert!(tx.try_send(()).is_err()); + + let then = Instant::now(); + tx.send(()).unwrap(); + let now = Instant::now(); + + assert!(now.duration_since(then) > Duration::from_millis(100), "iter = {}", i); + }); + + std::thread::sleep(Duration::from_millis(1000)); + rx.recv().unwrap(); + + t.join().unwrap(); + } +} + +#[test] +fn hydra() { + let thread_num = 32; + let msg_num = 1000; + + let (main_tx, main_rx) = unbounded::<()>(); + + let mut txs = Vec::new(); + for _ in 0..thread_num { + let main_tx = main_tx.clone(); + let (tx, rx) = unbounded(); + txs.push(tx); + + std::thread::spawn(move || { + for msg in rx.iter() { + main_tx.send(msg).unwrap(); + } + }); + } + + drop(main_tx); + + for _ in 0..10 { + for tx in &txs { + for _ in 0..msg_num { + tx.send(Default::default()).unwrap(); + } + } + + for _ in 0..thread_num { + for _ in 0..msg_num { + main_rx.recv().unwrap(); + } + } + } + + drop(txs); + assert!(main_rx.recv().is_err()); +} + +#[test] +fn robin() { + let thread_num = 32; + let msg_num = 10; + + let (mut main_tx, main_rx) = bounded::<()>(1); + + for _ in 0..thread_num { + let (mut tx, rx) = bounded(100); + std::mem::swap(&mut tx, &mut main_tx); + + std::thread::spawn(move || { + for msg in rx.iter() { + tx.send(msg).unwrap(); + } + }); + } + + for _ in 0..10 { + let main_tx = main_tx.clone(); + std::thread::spawn(move || { + for _ in 0..msg_num { + main_tx.send(Default::default()).unwrap(); + } + }); + + for _ in 0..msg_num { + main_rx.recv().unwrap(); + } + } +} + +#[cfg(feature = "select")] +#[test] +fn select_general() { + #[derive(Debug, PartialEq)] + struct Foo(usize); + + let (tx0, rx0) = bounded(1); + let (tx1, rx1) = unbounded(); + + for (i, t) in vec![tx0.clone(), tx1].into_iter().enumerate() { + std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + let _ = t.send(Foo(i)); + }); + } + + let x = Selector::new() + .recv(&rx0, |x| x) + .recv(&rx1, |x| x) + .wait() + .unwrap(); + + if x == Foo(0) { + assert!(rx1.recv().unwrap() == Foo(1)); + } else { + assert!(rx0.recv().unwrap() == Foo(0)); + } + + tx0.send(Foo(42)).unwrap(); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(100)); + assert_eq!(rx0.recv().unwrap(), Foo(42)); + assert_eq!(rx0.recv().unwrap(), Foo(43)); + + }); + + Selector::new() + .send(&tx0, Foo(43), |x| x) + .wait() + .unwrap(); + + t.join().unwrap(); +} + +struct MessageWithoutDebug(u32); + +#[test] +// This is a 'does it build' test, to make sure that the error types can turn +// into a std::error::Error without requiring the payload (which is not used +// there) to impl Debug. +fn std_error_without_debug() { + let (tx, rx) = unbounded::<MessageWithoutDebug>(); + + match tx.send(MessageWithoutDebug(1)) { + Ok(_) => {} + Err(e) => { + let _std_err: &dyn std::error::Error = &e; + } + } + + match rx.recv() { + Ok(_) => {} + Err(e) => { + let _std_err: &dyn std::error::Error = &e; + } + } + + match tx.try_send(MessageWithoutDebug(2)) { + Ok(_) => {} + Err(e) => { + let _std_err: &dyn std::error::Error = &e; + } + } + + match rx.try_recv() { + Ok(_) => {} + Err(e) => { + let _std_err: &dyn std::error::Error = &e; + } + } + + match tx.send_timeout(MessageWithoutDebug(3), Duration::from_secs(1000000)) { + Ok(_) => {} + Err(e) => { + let _std_err: &dyn std::error::Error = &e; + } + } + + match rx.recv_timeout(Duration::from_secs(10000000)) { + Ok(_) => {} + Err(e) => { + let _std_err: &dyn std::error::Error = &e; + } + } +} + +#[test] +fn weak_close() { + let (tx, rx) = unbounded::<()>(); + let weak = tx.downgrade(); + drop(tx); + assert!(weak.upgrade().is_none()); + assert!(rx.is_disconnected()); + assert!(rx.try_recv().is_err()); +} + +#[test] +fn weak_upgrade() { + let (tx, rx) = unbounded(); + let weak = tx.downgrade(); + let tx2 = weak.upgrade().unwrap(); + drop(tx); + assert!(!rx.is_disconnected()); + tx2.send(()).unwrap(); + assert!(rx.try_recv().is_ok()); +} diff --git a/vendor/flume/tests/check_same_channel.rs b/vendor/flume/tests/check_same_channel.rs new file mode 100644 index 0000000..edb82c3 --- /dev/null +++ b/vendor/flume/tests/check_same_channel.rs @@ -0,0 +1,57 @@ +#[test] +fn same_sender() { + let (tx1, _rx) = flume::unbounded::<()>(); + let tx2 = tx1.clone(); + + assert!(tx1.same_channel(&tx2)); + + let (tx3, _rx) = flume::unbounded::<()>(); + + assert!(!tx1.same_channel(&tx3)); + assert!(!tx2.same_channel(&tx3)); +} + +#[test] +fn same_receiver() { + let (_tx, rx1) = flume::unbounded::<()>(); + let rx2 = rx1.clone(); + + assert!(rx1.same_channel(&rx2)); + + let (_tx, rx3) = flume::unbounded::<()>(); + + assert!(!rx1.same_channel(&rx3)); + assert!(!rx2.same_channel(&rx3)); +} + +#[cfg(feature = "async")] +#[test] +fn same_send_sink() { + let (tx1, _rx) = flume::unbounded::<()>(); + let tx1 = tx1.into_sink(); + let tx2 = tx1.clone(); + + assert!(tx1.same_channel(&tx2)); + + let (tx3, _rx) = flume::unbounded::<()>(); + let tx3 = tx3.into_sink(); + + assert!(!tx1.same_channel(&tx3)); + assert!(!tx2.same_channel(&tx3)); +} + +#[cfg(feature = "async")] +#[test] +fn same_recv_stream() { + let (_tx, rx1) = flume::unbounded::<()>(); + let rx1 = rx1.into_stream(); + let rx2 = rx1.clone(); + + assert!(rx1.same_channel(&rx2)); + + let (_tx, rx3) = flume::unbounded::<()>(); + let rx3 = rx3.into_stream(); + + assert!(!rx1.same_channel(&rx3)); + assert!(!rx2.same_channel(&rx3)); +} diff --git a/vendor/flume/tests/golang.rs b/vendor/flume/tests/golang.rs new file mode 100644 index 0000000..ca00840 --- /dev/null +++ b/vendor/flume/tests/golang.rs @@ -0,0 +1,1445 @@ +// //! 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::any::Any; +// use std::cell::Cell; +// use std::collections::HashMap; +// use std::sync::{Arc, Condvar, Mutex}; +// use std::thread; +// use std::time::Duration; + +// use flume::{bounded, tick, Receiver, Select, Sender}; + +// fn ms(ms: u64) -> Duration { +// Duration::from_millis(ms) +// } + +// struct Chan<T> { +// inner: Arc<Mutex<ChanInner<T>>>, +// } + +// struct ChanInner<T> { +// s: Option<Sender<T>>, +// r: Receiver<T>, +// } + +// impl<T> Clone for Chan<T> { +// fn clone(&self) -> Chan<T> { +// Chan { +// inner: self.inner.clone(), +// } +// } +// } + +// impl<T> Chan<T> { +// 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<T> { +// let r = self.inner.lock().unwrap().r.clone(); +// r.try_recv().ok() +// } + +// fn recv(&self) -> Option<T> { +// 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<T> { +// self.inner.lock().unwrap().r.clone() +// } + +// fn tx(&self) -> Sender<T> { +// match self.inner.lock().unwrap().s.as_ref() { +// None => { +// let (s, r) = bounded(0); +// std::mem::forget(r); +// s +// } +// Some(s) => s.clone(), +// } +// } +// } + +// impl<T> Iterator for Chan<T> { +// type Item = T; + +// fn next(&mut self) -> Option<Self::Item> { +// self.recv() +// } +// } + +// impl<'a, T> IntoIterator for &'a Chan<T> { +// type Item = T; +// type IntoIter = Chan<T>; + +// fn into_iter(self) -> Self::IntoIter { +// self.clone() +// } +// } + +// fn make<T>(cap: usize) -> Chan<T> { +// let (s, r) = bounded(cap); +// Chan { +// inner: Arc::new(Mutex::new(ChanInner { s: Some(s), r })), +// } +// } + +// #[derive(Clone)] +// struct WaitGroup(Arc<WaitGroupInner>); + +// struct WaitGroupInner { +// cond: Condvar, +// count: Mutex<i32>, +// } + +// 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: FnOnce()> { +// f: Option<Box<F>>, +// } + +// impl<F: FnOnce()> Drop for Defer<F> { +// fn drop(&mut self) { +// let f = self.f.take().unwrap(); +// let mut f = Some(f); +// let mut f = move || f.take().unwrap()(); +// f(); +// } +// } + +// 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<i32>, c2: Chan<i32>, c3: Chan<i32>, c4: Chan<i32>) { +// 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<i32>, inp: Chan<i32>, done: Chan<bool>) { +// for v in inp { +// out.send(v); +// } +// done.send(true); +// } + +// fn recver(inp: Chan<i32>) { +// 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::<i32>(0); +// let c2 = make::<i32>(0); +// let c3 = make::<i32>(0); +// let c4 = make::<i32>(0); +// let done = make::<bool>(0); +// let cmux = make::<i32>(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::<i32>(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<i32>, val: i32, inp: Chan<i32>, out: Chan<i32>) { +// inp.recv(); +// if ch.recv() != Some(val) { +// panic!(val); +// } +// out.send(1); +// } + +// #[test] +// fn synch_fifo() { +// let ch = make::<i32>(0); +// let mut inp = make::<i32>(0); +// let start = inp.clone(); + +// for i in 0..N { +// let out = make::<i32>(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<i32>, right: Chan<i32>) { +// left.send(right.recv().unwrap()); +// } + +// #[test] +// fn main() { +// let n = 100i32; + +// let leftmost = make::<i32>(0); +// let mut right = leftmost.clone(); +// let mut left = leftmost.clone(); + +// for _ in 0..n { +// right = make::<i32>(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<i32>, strobe: Chan<bool>) { +// if c.recv().unwrap() != 123 { +// panic!("i32 value"); +// } +// strobe.send(true); +// } + +// fn i32sender(c: Chan<i32>, strobe: Chan<bool>) { +// c.send(234); +// strobe.send(true); +// } + +// fn i64receiver(c: Chan<i64>, strobe: Chan<bool>) { +// if c.recv().unwrap() != 123456 { +// panic!("i64 value"); +// } +// strobe.send(true); +// } + +// fn i64sender(c: Chan<i64>, strobe: Chan<bool>) { +// c.send(234567); +// strobe.send(true); +// } + +// fn breceiver(c: Chan<bool>, strobe: Chan<bool>) { +// if !c.recv().unwrap() { +// panic!("b value"); +// } +// strobe.send(true); +// } + +// fn bsender(c: Chan<bool>, strobe: Chan<bool>) { +// c.send(true); +// strobe.send(true); +// } + +// fn sreceiver(c: Chan<String>, strobe: Chan<bool>) { +// if c.recv().unwrap() != "hello" { +// panic!("x value"); +// } +// strobe.send(true); +// } + +// fn ssender(c: Chan<String>, strobe: Chan<bool>) { +// 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::<bool>(0); + +// for buffer in 0..2 { +// let c32 = make::<i32>(buffer); +// let c64 = make::<i64>(buffer); +// let cb = make::<bool>(buffer); +// let cs = make::<String>(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 try = 0; +// loop { +// select! { +// send(c32.tx(), 123) -> _ => break, +// default => { +// try += 1; +// if 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 try = 0; +// loop { +// select! { +// recv(c32.rx()) -> v => { +// if v != Ok(234) { +// panic!("i32sender value"); +// } +// break; +// } +// default => { +// try += 1; +// if try > MAX_TRIES { +// println!("i32sender buffer={}", buffer); +// panic!("fail"); +// } +// sleep(); +// } +// } +// } +// if buffer == 0 { +// sync.recv(); +// } + +// go!(c64, sync, i64receiver(c64, sync)); +// let mut try = 0; +// loop { +// select! { +// send(c64.tx(), 123456) -> _ => break, +// default => { +// try += 1; +// if 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 try = 0; +// loop { +// select! { +// recv(c64.rx()) -> v => { +// if v != Ok(234567) { +// panic!("i64sender value"); +// } +// break; +// } +// default => { +// try += 1; +// if try > MAX_TRIES { +// println!("i64sender buffer={}", buffer); +// panic!("fail"); +// } +// sleep(); +// } +// } +// } +// if buffer == 0 { +// sync.recv(); +// } + +// go!(cb, sync, breceiver(cb, sync)); +// let mut try = 0; +// loop { +// select! { +// send(cb.tx(), true) -> _ => break, +// default => { +// try += 1; +// if 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 try = 0; +// loop { +// select! { +// recv(cb.rx()) -> v => { +// if v != Ok(true) { +// panic!("bsender value"); +// } +// break; +// } +// default => { +// try += 1; +// if try > MAX_TRIES { +// println!("bsender buffer={}", buffer); +// panic!("fail"); +// } +// sleep(); +// } +// } +// } +// if buffer == 0 { +// sync.recv(); +// } + +// go!(cs, sync, sreceiver(cs, sync)); +// let mut try = 0; +// loop { +// select! { +// send(cs.tx(), "hello".to_string()) -> _ => break, +// default => { +// try += 1; +// if 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 try = 0; +// loop { +// select! { +// recv(cs.rx()) -> v => { +// if v != Ok("hello again".to_string()) { +// panic!("ssender value"); +// } +// break; +// } +// default => { +// try += 1; +// if 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<u32>>, mut b: Option<&Chan<u32>>| { +// let mut i = 0; +// let never = make::<u32>(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::<u32>(1); +// let b = make::<u32>(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 { +// // TODO +// } + +// // 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::<i32>(1); +// let c1 = make::<i32>(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::<bool>(0); +// let c2 = make::<bool>(0); +// let c3 = make::<bool>(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<i32>) { +// c.recv().unwrap(); +// } + +// fn recv2(c: Chan<i32>) { +// select! { +// recv(c.rx()) -> _ => () +// } +// } + +// fn recv3(c: Chan<i32>) { +// let c2 = make::<i32>(1); +// select! { +// recv(c.rx()) -> _ => (), +// recv(c2.rx()) -> _ => () +// } +// } + +// fn send1(recv: fn(Chan<i32>)) { +// let c = make::<i32>(1); +// go!(c, recv(c)); +// thread::yield_now(); +// c.send(1); +// } + +// fn send2(recv: fn(Chan<i32>)) { +// let c = make::<i32>(1); +// go!(c, recv(c)); +// thread::yield_now(); +// select! { +// send(c.tx(), 1) -> _ => () +// } +// } + +// fn send3(recv: fn(Chan<i32>)) { +// let c = make::<i32>(1); +// go!(c, recv(c)); +// thread::yield_now(); +// let c2 = make::<i32>(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<i32>) { +// let mut i = 2; +// loop { +// ch.send(i); +// i += 1; +// } +// } + +// fn filter(in_ch: Chan<i32>, out_ch: Chan<i32>, prime: i32) { +// for i in in_ch { +// if i % prime != 0 { +// out_ch.send(i); +// } +// } +// } + +// fn sieve(primes: Chan<i32>) { +// let mut ch = make::<i32>(1); +// go!(ch, generate(ch)); +// loop { +// let prime = ch.recv().unwrap(); +// primes.send(prime); + +// let ch1 = make::<i32>(1); +// go!(ch, ch1, prime, filter(ch, ch1, prime)); +// ch = ch1; +// } +// } + +// #[test] +// fn main() { +// let primes = make::<i32>(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::<ZeroSize>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(cap as usize); +// let done = make::<bool>(0); + +// go!(c, done, { +// let v = c.try_recv(); +// done.send(v.is_some()); +// }); + +// 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::<i32>(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::<i32>(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::<bool>(1); +// for _ in 0..N { +// let c1 = make::<i32>(1); +// let c2 = make::<i32>(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::<bool>(1); +// for _ in 0..N { +// let c1 = make::<i32>(1); +// let c2 = make::<i32>(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::<i32>(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::<i32>(0), +// make::<i32>(0), +// make::<i32>(2), +// make::<i32>(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::<Vec<_>>(); + +// 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::<Vec<_>>(); + +// 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::<u8>(TRIALS + 1); +// let c2 = make::<u8>(TRIALS + 1); + +// for _ in 0..TRIALS + 1 { +// c1.send(1); +// c2.send(2); +// } + +// let c3 = make::<u8>(0); +// let c4 = make::<u8>(0); +// let out = make::<u8>(0); +// let done = make::<u8>(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::<Box<dyn Any>>(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::<i32>(cap); +// let l = Arc::new(Mutex::new(vec![0i32; N])); +// let done = make::<bool>(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::<i32>(NWORK * 3); +// let r = make::<i32>(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::<i32>(0); +// let d = make::<i32>(0); +// let e = make::<i32>(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/vendor/flume/tests/iter.rs b/vendor/flume/tests/iter.rs new file mode 100644 index 0000000..4d69adb --- /dev/null +++ b/vendor/flume/tests/iter.rs @@ -0,0 +1,112 @@ +//! Tests for iteration over receivers. + +extern crate crossbeam_utils; + +use flume::unbounded; +use crossbeam_utils::thread::scope; + +#[test] +fn nested_recv_iter() { + let (s, r) = unbounded::<i32>(); + let (total_s, total_r) = unbounded::<i32>(); + + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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/vendor/flume/tests/list.rs b/vendor/flume/tests/list.rs new file mode 100644 index 0000000..851af88 --- /dev/null +++ b/vendor/flume/tests/list.rs @@ -0,0 +1,536 @@ +//! Tests for the list channel flavor. + +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use flume::{unbounded, Receiver}; +use flume::{RecvError, RecvTimeoutError, TryRecvError}; +use flume::{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!(r.recv().is_err()); + }); + 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::<i32>(); + + 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!(r.recv().is_err()); +} + +#[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!(r.recv().is_err()); + }); + 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!(r.recv().is_err()); + }); + 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::<usize>(); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>(); + + 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::<DropCounter>(); + + 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<dyn Any + Send>; + + let (s, r) = unbounded::<T>(); + + 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::<Option<Receiver<T>>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/flume/tests/method_sharing.rs b/vendor/flume/tests/method_sharing.rs new file mode 100644 index 0000000..24173ea --- /dev/null +++ b/vendor/flume/tests/method_sharing.rs @@ -0,0 +1,39 @@ +#[cfg(feature = "async")] +use flume::*; + +#[cfg(feature = "async")] +#[async_std::test] +async fn sender() { + let (sender, receiver) = bounded(1); + + let sender_fut = sender.send_async(()); + assert_eq!(sender.is_disconnected(), sender_fut.is_disconnected()); + assert_eq!(sender.is_empty(), sender_fut.is_empty()); + assert_eq!(sender.is_full(), sender_fut.is_full()); + assert_eq!(sender.len(), sender_fut.len()); + assert_eq!(sender.capacity(), sender_fut.capacity()); + + let sender_sink = sender.sink(); + assert_eq!(sender.is_disconnected(), sender_sink.is_disconnected()); + assert_eq!(sender.is_empty(), sender_sink.is_empty()); + assert_eq!(sender.is_full(), sender_sink.is_full()); + assert_eq!(sender.len(), sender_sink.len()); + assert_eq!(sender.capacity(), sender_sink.capacity()); + + let receiver_fut = receiver.recv_async(); + assert_eq!(receiver.is_disconnected(), receiver_fut.is_disconnected()); + assert_eq!(receiver.is_empty(), receiver_fut.is_empty()); + assert_eq!(receiver.is_full(), receiver_fut.is_full()); + assert_eq!(receiver.len(), receiver_fut.len()); + assert_eq!(receiver.capacity(), receiver_fut.capacity()); + + let receiver_stream = receiver.stream(); + assert_eq!( + receiver.is_disconnected(), + receiver_stream.is_disconnected() + ); + assert_eq!(receiver.is_empty(), receiver_stream.is_empty()); + assert_eq!(receiver.is_full(), receiver_stream.is_full()); + assert_eq!(receiver.len(), receiver_stream.len()); + assert_eq!(receiver.capacity(), receiver_stream.capacity()); +} diff --git a/vendor/flume/tests/mpsc.rs b/vendor/flume/tests/mpsc.rs new file mode 100644 index 0000000..213b9d8 --- /dev/null +++ b/vendor/flume/tests/mpsc.rs @@ -0,0 +1,2095 @@ +//! 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 + +#[macro_use] +extern crate crossbeam_channel as cc; + +use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; +use std::sync::mpsc::{SendError, TrySendError}; +use std::thread::JoinHandle; +use std::time::Duration; + +pub struct Sender<T> { + pub inner: cc::Sender<T>, +} + +impl<T> Sender<T> { + pub fn send(&self, t: T) -> Result<(), SendError<T>> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } +} + +impl<T> Clone for Sender<T> { + fn clone(&self) -> Sender<T> { + Sender { + inner: self.inner.clone(), + } + } +} + +pub struct SyncSender<T> { + pub inner: cc::Sender<T>, +} + +impl<T> SyncSender<T> { + pub fn send(&self, t: T) -> Result<(), SendError<T>> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } + + pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> { + 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<T> Clone for SyncSender<T> { + fn clone(&self) -> SyncSender<T> { + SyncSender { + inner: self.inner.clone(), + } + } +} + +pub struct Receiver<T> { + pub inner: cc::Receiver<T>, +} + +impl<T> Receiver<T> { + pub fn try_recv(&self) -> Result<T, TryRecvError> { + self.inner.try_recv().map_err(|err| match err { + cc::TryRecvError::Empty => TryRecvError::Empty, + cc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + pub fn recv(&self) -> Result<T, RecvError> { + self.inner.recv().map_err(|_| RecvError) + } + + pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> { + 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<T> { + Iter { inner: self } + } + + pub fn try_iter(&self) -> TryIter<T> { + TryIter { inner: self } + } +} + +impl<'a, T> IntoIterator for &'a Receiver<T> { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<T> IntoIterator for Receiver<T> { + type Item = T; + type IntoIter = IntoIter<T>; + + fn into_iter(self) -> IntoIter<T> { + IntoIter { inner: self } + } +} + +pub struct TryIter<'a, T: 'a> { + inner: &'a Receiver<T>, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option<T> { + self.inner.try_recv().ok() + } +} + +pub struct Iter<'a, T: 'a> { + inner: &'a Receiver<T>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option<T> { + self.inner.recv().ok() + } +} + +pub struct IntoIter<T> { + inner: Receiver<T>, +} + +impl<T> Iterator for IntoIter<T> { + type Item = T; + + fn next(&mut self) -> Option<T> { + self.inner.recv().ok() + } +} + +pub fn channel<T>() -> (Sender<T>, Receiver<T>) { + let (s, r) = cc::unbounded(); + let s = Sender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) { + 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),+ + ) => ({ + 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::<i32>(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = channel::<Box<isize>>(); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn drop_full_shared() { + let (tx, _rx) = channel::<Box<isize>>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = channel::<i32>(); + 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::<i32>(); + 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::<i32>(); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone() { + let (tx, rx) = channel::<i32>(); + drop(rx); + assert!(tx.send(1).is_err()) + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = channel::<i32>(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = channel::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + let (tx2, rx2) = channel::<i32>(); + 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::<i32>(); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::<i32>(); + 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::<Box<i32>>(); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = channel::<i32>(); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::<Box<i32>>(); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::<i32>(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::<i32>(); + drop(rx); + assert!(tx.send(10).is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::<i32>(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::<i32>(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::<i32>(); + 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::<i32>(); + 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::<i32>(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::<Box<i32>>(); + 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::<Box<i32>>(); + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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::<Box<isize>>(); + 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<Box<i32>>, i: i32) -> Option<JoinHandle<()>> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver<Box<i32>>, i: i32) -> Option<JoinHandle<()>> { + 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::<i32>(); + let (total_tx, total_rx) = channel::<i32>(); + + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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::<i32>(); + 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::<i32>(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = sync_channel::<Box<isize>>(1); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = sync_channel::<i32>(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::<i32>(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::<i32>(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::<i32>(0); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = sync_channel::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(0); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = sync_channel::<i32>(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::<Box<i32>>(0); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = sync_channel::<i32>(0); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = sync_channel::<Box<i32>>(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::<i32>(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::<i32>(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::<i32>(0); + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = sync_channel::<i32>(1); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = sync_channel::<i32>(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_closed_with_data() { + let (tx, rx) = sync_channel::<i32>(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::<i32>(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::<i32>(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::<i32>(0); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = sync_channel::<Box<i32>>(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::<Box<i32>>(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::<i32>(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::<i32>(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::<i32>(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::<Box<i32>>(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::<Box<i32>>(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<Box<i32>>, i: i32) -> Option<JoinHandle<()>> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver<Box<i32>>, i: i32) -> Option<JoinHandle<()>> { + 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::<i32>(0); + let (total_tx, total_rx) = sync_channel::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(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::<i32>(0); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send2() { + let (tx, _rx) = sync_channel::<i32>(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::<i32>(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::<i32>(); + let (tx2, rx2) = channel::<i32>(); + 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::<i32>(); + let (_tx2, rx2) = channel::<i32>(); + let (_tx3, rx3) = channel::<i32>(); + let (_tx4, rx4) = channel::<i32>(); + let (tx5, rx5) = channel::<i32>(); + 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::<i32>(); + let (tx2, rx2) = channel::<i32>(); + drop(tx2); + + select! { + _a1 = rx1.recv() => { panic!() }, + a2 = rx2.recv() => { assert!(a2.is_err()); } + } + } + + #[test] + fn unblocks() { + let (tx1, rx1) = channel::<i32>(); + let (_tx2, rx2) = channel::<i32>(); + let (tx3, rx3) = channel::<i32>(); + + 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::<i32>(); + let (tx2, rx2) = channel::<i32>(); + 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::<i32>(); + let (tx2, rx2) = channel::<i32>(); + 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::<i32>(); + let (_tx2, rx2) = channel::<i32>(); + 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::<i32>(); + let (_tx2, rx2) = channel::<i32>(); + 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::<i32>(1); + tx.send(1).unwrap(); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + } + + #[test] + fn sync2() { + let (tx, rx) = sync_channel::<i32>(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::<i32>(0); + let (tx2, rx2): (Sender<i32>, Receiver<i32>) = 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/vendor/flume/tests/never.rs b/vendor/flume/tests/never.rs new file mode 100644 index 0000000..676903f --- /dev/null +++ b/vendor/flume/tests/never.rs @@ -0,0 +1,99 @@ +// //! Tests for the never channel flavor. + +// #[macro_use] +// extern crate crossbeam_channel; +// extern crate rand; + +// use std::thread; +// use std::time::{Duration, Instant}; + +// use crossbeam_channel::{never, tick, unbounded}; + +// fn ms(ms: u64) -> Duration { +// Duration::from_millis(ms) +// } + +// #[test] +// fn smoke() { +// select! { +// recv(never::<i32>()) -> _ => panic!(), +// default => {} +// } +// } + +// #[test] +// fn optional() { +// let (s, r) = unbounded::<i32>(); +// 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::<i32>(); +// assert_eq!(r.capacity(), Some(0)); +// } + +// #[test] +// fn len_empty_full() { +// let r = never::<i32>(); +// assert_eq!(r.len(), 0); +// assert_eq!(r.is_empty(), true); +// assert_eq!(r.is_full(), true); +// } + +// #[test] +// fn try_recv() { +// let r = never::<i32>(); +// 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::<i32>(); + +// 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/vendor/flume/tests/ready.rs b/vendor/flume/tests/ready.rs new file mode 100644 index 0000000..2f42d9a --- /dev/null +++ b/vendor/flume/tests/ready.rs @@ -0,0 +1,837 @@ +// //! Tests for channel readiness using the `Select` struct. + +// extern crate crossbeam_channel; +// extern crate crossbeam_utils; + +// 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::<usize>(); +// let (s2, r2) = unbounded::<usize>(); + +// 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::<i32>(); +// let (_s2, r2) = unbounded::<i32>(); +// let (_s3, r3) = unbounded::<i32>(); +// let (_s4, r4) = unbounded::<i32>(); +// let (s5, r5) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(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::<i32>(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::<i32>(0); +// let (s2, r2) = bounded::<i32>(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::<i32>(); +// let (_s2, r2) = unbounded::<i32>(); +// 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::<i32>(); +// 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::<i32>(); + +// 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::<i32>(0); +// let mut sel = Select::new(); +// sel.send(&s); +// sel.recv(&r); +// assert!(sel.ready_timeout(ms(100)).is_err()); + +// let (s, r) = unbounded::<i32>(); +// 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<dyn Any + Send>; + +// for cap in 1..4 { +// let (s, r) = bounded::<T>(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::<Option<Receiver<T>>>() +// .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 = 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(); +// 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() >= COUNT / hits.len() / 10)); +// }) +// .unwrap(); +// } diff --git a/vendor/flume/tests/same_channel.rs b/vendor/flume/tests/same_channel.rs new file mode 100644 index 0000000..c6452ec --- /dev/null +++ b/vendor/flume/tests/same_channel.rs @@ -0,0 +1,114 @@ +// extern crate crossbeam_channel; + +// 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::<usize>(1); + +// let s2 = s.clone(); +// assert!(s.same_channel(&s2)); + +// let r2 = r.clone(); +// assert!(r.same_channel(&r2)); + +// let (s3, r3) = bounded::<usize>(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::<usize>(); + +// let s2 = s.clone(); +// assert!(s.same_channel(&s2)); + +// let r2 = r.clone(); +// assert!(r.same_channel(&r2)); + +// let (s3, r3) = unbounded::<usize>(); +// 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::<usize>(); + +// let r2 = r.clone(); +// assert!(r.same_channel(&r2)); + +// // Never channel are always equal to one another. +// let r3 = never::<usize>(); +// 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::<usize>(0); + +// let s2 = s.clone(); +// assert!(s.same_channel(&s2)); + +// let r2 = r.clone(); +// assert!(r.same_channel(&r2)); + +// let (s3, r3) = bounded::<usize>(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::<usize>(0); +// let (s2, r2) = unbounded::<usize>(); + +// assert!(!s1.same_channel(&s2)); +// assert!(!r1.same_channel(&r2)); +// } diff --git a/vendor/flume/tests/select.rs b/vendor/flume/tests/select.rs new file mode 100644 index 0000000..4fac9e9 --- /dev/null +++ b/vendor/flume/tests/select.rs @@ -0,0 +1,1304 @@ +// //! Tests for channel selection using the `Select` struct. + +// extern crate crossbeam_channel; +// extern crate crossbeam_utils; + +// 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::<usize>(); +// let (s2, r2) = unbounded::<usize>(); + +// 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::<i32>(); +// let (_s2, r2) = unbounded::<i32>(); +// let (_s3, r3) = unbounded::<i32>(); +// let (_s4, r4) = unbounded::<i32>(); +// let (s5, r5) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(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::<i32>(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::<i32>(0); +// let (s2, r2) = bounded::<i32>(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::<i32>(0); +// let (s2, r2) = bounded::<i32>(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::<i32>(); +// let (_s2, r2) = unbounded::<i32>(); +// 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::<i32>(); +// 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::<i32>(); + +// 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::<i32>(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::<i32>(); +// 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::<usize>(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::<usize>(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<dyn Any + Send>; + +// for cap in 0..3 { +// let (s, r) = bounded::<T>(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::<Option<Receiver<T>>>() +// .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::<i32>(1), bounded::<i32>(1)) +// } else { +// (unbounded::<i32>(), unbounded::<i32>()) +// }; + +// 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::<i32>(1), bounded::<i32>(1)) +// } else { +// (unbounded::<i32>(), unbounded::<i32>()) +// }; + +// 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::<usize>(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::<usize>(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/vendor/flume/tests/select_macro.rs b/vendor/flume/tests/select_macro.rs new file mode 100644 index 0000000..367d8dd --- /dev/null +++ b/vendor/flume/tests/select_macro.rs @@ -0,0 +1,1440 @@ +// //! Tests for the `select!` macro. + +// #![deny(unsafe_code)] + +// #[macro_use] +// extern crate crossbeam_channel; +// extern crate crossbeam_utils; + +// 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, 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::<usize>(); +// let (s2, r2) = unbounded::<usize>(); + +// 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::<i32>(); +// let (_s2, r2) = unbounded::<i32>(); +// let (_s3, r3) = unbounded::<i32>(); +// let (_s4, r4) = unbounded::<i32>(); +// let (s5, r5) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); +// let (s2, r2) = unbounded::<i32>(); + +// 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::<i32>(); + +// 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::<i32>(); + +// select! { +// recv(r) -> res => assert!(res.is_err()), +// default => panic!(), +// } + +// let (_, r) = unbounded::<i32>(); + +// select! { +// recv(r) -> res => assert!(res.is_err()), +// default(ms(1000)) => panic!(), +// } + +// let (s, _) = bounded::<i32>(0); + +// select! { +// send(s, 0) -> res => assert!(res.is_err()), +// default => panic!(), +// } + +// let (s, _) = bounded::<i32>(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::<i32>(0); +// let (s2, r2) = bounded::<i32>(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::<i32>(0); +// let (s2, r2) = bounded::<i32>(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::<i32>(); +// let (_s2, r2) = unbounded::<i32>(); +// 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::<i32>(); +// 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::<i32>(); + +// 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<i32> { +// panic!("send panicked") +// } + +// #[allow(unreachable_code)] +// { +// select! { +// send(get(), panic!()) -> _ => {} +// } +// } +// } + +// #[test] +// #[should_panic(expected = "recv panicked")] +// fn panic_receiver() { +// fn get() -> Receiver<i32> { +// 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::<i32>(0); +// select! { +// send(s, 0) -> _ => panic!(), +// recv(r) -> _ => panic!(), +// default(ms(500)) => {} +// } + +// let (s, r) = unbounded::<i32>(); +// select! { +// send(s, 0) -> _ => {}, +// recv(r) -> _ => panic!(), +// default(ms(500)) => panic!(), +// } +// } + +// #[test] +// fn matching() { +// const THREADS: usize = 44; + +// let (s, r) = &bounded::<usize>(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::<usize>(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<dyn Any + Send>; + +// for cap in 0..3 { +// let (s, r) = bounded::<T>(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::<Option<Receiver<T>>>() +// .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::<i32>(1), bounded::<i32>(1)) +// } else { +// (unbounded::<i32>(), unbounded::<i32>()) +// }; + +// 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::<i32>(1), bounded::<i32>(1)) +// } else { +// (unbounded::<i32>(), unbounded::<i32>()) +// }; + +// 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::<i32>(); +// 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::<i32>(); + +// 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::<i32>(); +// 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::<i32>(0); + +// select! { +// recv(r) -> _ => panic!(), +// default => {} +// } +// select! { +// send(s, 0) -> _ => panic!(), +// default() => {} +// } +// select! { +// default => {} +// } +// select! { +// default() => {} +// } +// } + +// #[test] +// fn same_variable_name() { +// let (_, r) = unbounded::<i32>(); +// select! { +// recv(r) -> r => assert!(r.is_err()), +// } +// } + +// #[test] +// fn handles_on_heap() { +// let (s, r) = unbounded::<i32>(); +// 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::<i32>(); + +// 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::<i32>(); + +// let once = Box::new(()); +// let get = move || { +// drop(once); +// r +// }; + +// select! { +// recv(get()) -> _ => {} +// } +// } + +// #[test] +// fn once_sender() { +// let (s, _) = unbounded::<i32>(); + +// let once = Box::new(()); +// let get = move || { +// drop(once); +// s +// }; + +// select! { +// send(get(), 5) -> _ => {} +// } +// } + +// #[test] +// fn parse_nesting() { +// let (_, r) = unbounded::<i32>(); + +// select! { +// recv(r) -> _ => {} +// recv(r) -> _ => { +// select! { +// recv(r) -> _ => {} +// recv(r) -> _ => { +// select! { +// recv(r) -> _ => {} +// recv(r) -> _ => { +// select! { +// default => {} +// } +// } +// } +// } +// } +// } +// } +// } + +// #[test] +// fn evaluate() { +// let (s, r) = unbounded::<i32>(); + +// 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<T>(cc::Sender<T>); +// struct Receiver<T>(cc::Receiver<T>); + +// impl<T> Deref for Receiver<T> { +// type Target = cc::Receiver<T>; + +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } + +// impl<T> Deref for Sender<T> { +// type Target = cc::Sender<T>; + +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } + +// let (s, r) = bounded::<i32>(0); +// let (s, r) = (Sender(s), Receiver(r)); + +// select! { +// send(s, 0) -> _ => panic!(), +// recv(r) -> _ => panic!(), +// default => {} +// } +// } + +// #[test] +// fn result_types() { +// let (s, _) = bounded::<i32>(0); +// let (_, r) = bounded::<i32>(0); + +// select! { +// recv(r) -> res => drop::<Result<i32, RecvError>>(res), +// } +// select! { +// recv(r) -> res => drop::<Result<i32, RecvError>>(res), +// default => {} +// } +// select! { +// recv(r) -> res => drop::<Result<i32, RecvError>>(res), +// default(ms(0)) => {} +// } + +// select! { +// send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res), +// } +// select! { +// send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res), +// default => {} +// } +// select! { +// send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res), +// default(ms(0)) => {} +// } + +// select! { +// send(s, 0) -> res => drop::<Result<(), SendError<i32>>>(res), +// recv(r) -> res => drop::<Result<i32, RecvError>>(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::<i32>(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/vendor/flume/tests/stream.rs b/vendor/flume/tests/stream.rs new file mode 100644 index 0000000..e3b32cd --- /dev/null +++ b/vendor/flume/tests/stream.rs @@ -0,0 +1,255 @@ +#[cfg(feature = "async")] +use { + flume::*, + futures::{stream::FuturesUnordered, StreamExt, TryFutureExt}, + async_std::prelude::FutureExt, + std::time::Duration, +}; +use futures::{stream, Stream}; + +#[cfg(feature = "async")] +#[test] +fn stream_recv() { + let (tx, rx) = unbounded(); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + tx.send(42u32).unwrap(); + println!("sent"); + }); + + async_std::task::block_on(async { + println!("receiving..."); + let x = rx.stream().next().await; + println!("received"); + assert_eq!(x, Some(42)); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn stream_recv_disconnect() { + let (tx, rx) = bounded::<i32>(0); + + let t = std::thread::spawn(move || { + tx.send(42); + std::thread::sleep(std::time::Duration::from_millis(250)); + drop(tx) + }); + + async_std::task::block_on(async { + let mut stream = rx.into_stream(); + assert_eq!(stream.next().await, Some(42)); + assert_eq!(stream.next().await, None); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn stream_recv_drop_recv() { + let (tx, rx) = bounded::<i32>(10); + + let rx2 = rx.clone(); + let mut stream = rx.into_stream(); + + async_std::task::block_on(async { + let res = async_std::future::timeout( + std::time::Duration::from_millis(500), + stream.next() + ).await; + + assert!(res.is_err()); + }); + + let t = std::thread::spawn(move || { + async_std::task::block_on(async { + rx2.stream().next().await + }) + }); + + std::thread::sleep(std::time::Duration::from_millis(500)); + + tx.send(42).unwrap(); + + drop(stream); + + assert_eq!(t.join().unwrap(), Some(42)) +} + +#[cfg(feature = "async")] +#[test] +fn r#stream_drop_send_disconnect() { + let (tx, rx) = bounded::<i32>(1); + + let t = std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_millis(250)); + drop(tx); + }); + + async_std::task::block_on(async { + let mut stream = rx.into_stream(); + assert_eq!(stream.next().await, None); + }); + + t.join().unwrap(); +} + +#[cfg(feature = "async")] +#[async_std::test] +async fn stream_send_1_million_no_drop_or_reorder() { + #[derive(Debug)] + enum Message { + Increment { + old: u64, + }, + ReturnCount, + } + + let (tx, rx) = unbounded(); + + let t = async_std::task::spawn(async move { + let mut count = 0u64; + let mut stream = rx.into_stream(); + + while let Some(Message::Increment { old }) = stream.next().await { + assert_eq!(old, count); + count += 1; + } + + count + }); + + for next in 0..1_000_000 { + tx.send(Message::Increment { old: next }).unwrap(); + } + + tx.send(Message::ReturnCount).unwrap(); + + let count = t.await; + assert_eq!(count, 1_000_000) +} + +#[cfg(feature = "async")] +#[async_std::test] +async fn parallel_streams_and_async_recv() { + let (tx, rx) = flume::unbounded(); + let rx = ℞ + let send_fut = async move { + let n_sends: usize = 100000; + for _ in 0..n_sends { + tx.send_async(()).await.unwrap(); + } + }; + + async_std::task::spawn( + send_fut + .timeout(Duration::from_secs(5)) + .map_err(|_| panic!("Send timed out!")) + ); + + let mut futures_unordered = (0..250) + .map(|n| async move { + if n % 2 == 0 { + let mut stream = rx.stream(); + while let Some(()) = stream.next().await {} + } else { + while let Ok(()) = rx.recv_async().await {} + } + + }) + .collect::<FuturesUnordered<_>>(); + + let recv_fut = async { + while futures_unordered.next().await.is_some() {} + }; + + recv_fut + .timeout(Duration::from_secs(5)) + .map_err(|_| panic!("Receive timed out!")) + .await + .unwrap(); +} + +#[cfg(feature = "async")] +#[test] +fn stream_no_double_wake() { + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::Arc; + use std::pin::Pin; + use std::task::Context; + use futures::task::{waker, ArcWake}; + use futures::Stream; + + let count = Arc::new(AtomicUsize::new(0)); + + // all this waker does is count how many times it is called + struct CounterWaker { + count: Arc<AtomicUsize>, + } + + impl ArcWake for CounterWaker { + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.count.fetch_add(1, Ordering::SeqCst); + } + } + + // create waker and context + let w = CounterWaker { + count: count.clone(), + }; + let w = waker(Arc::new(w)); + let cx = &mut Context::from_waker(&w); + + // create unbounded channel + let (tx, rx) = unbounded::<()>(); + let mut stream = rx.stream(); + + // register waker with stream + let _ = Pin::new(&mut stream).poll_next(cx); + + // send multiple items + tx.send(()).unwrap(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + + // verify that stream is only woken up once. + assert_eq!(count.load(Ordering::SeqCst), 1); +} + +#[cfg(feature = "async")] +#[async_std::test] +async fn stream_forward_issue_55() { // https://github.com/zesterer/flume/issues/55 + fn dummy_stream() -> impl Stream<Item = usize> { + stream::unfold(0, |count| async move { + if count < 1000 { + Some((count, count + 1)) + } else { + None + } + }) + } + + let (send_task, recv_task) = { + use futures::SinkExt; + let (tx, rx) = flume::bounded(100); + + let send_task = dummy_stream() + .map(|i| Ok(i)) + .forward(tx.into_sink().sink_map_err(|e| { + panic!("send error:{:#?}", e) + })); + + let recv_task = rx + .into_stream() + .for_each(|item| async move {}); + (send_task, recv_task) + }; + + let jh = async_std::task::spawn(send_task); + async_std::task::block_on(recv_task); + jh.await.unwrap(); +} diff --git a/vendor/flume/tests/thread_locals.rs b/vendor/flume/tests/thread_locals.rs new file mode 100644 index 0000000..acde751 --- /dev/null +++ b/vendor/flume/tests/thread_locals.rs @@ -0,0 +1,53 @@ +// //! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. + +// extern crate crossbeam_utils; + +// use std::thread; +// use std::time::Duration; + +// use flume::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/vendor/flume/tests/tick.rs b/vendor/flume/tests/tick.rs new file mode 100644 index 0000000..b0fcd44 --- /dev/null +++ b/vendor/flume/tests/tick.rs @@ -0,0 +1,353 @@ +// //! Tests for the tick channel flavor. + +// #[macro_use] +// extern crate crossbeam_channel; +// extern crate crossbeam_utils; +// extern crate rand; + +// use std::sync::atomic::AtomicUsize; +// use std::sync::atomic::Ordering; +// use std::thread; +// use std::time::{Duration, Instant}; + +// use crossbeam_channel::{after, 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/vendor/flume/tests/zero.rs b/vendor/flume/tests/zero.rs new file mode 100644 index 0000000..be4239d --- /dev/null +++ b/vendor/flume/tests/zero.rs @@ -0,0 +1,557 @@ +//! Tests for the zero channel flavor. + +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use flume::{bounded, Receiver}; +use flume::{RecvError, RecvTimeoutError, TryRecvError}; +use flume::{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!(r.recv().is_err()); + }); + 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::<i32>(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!(r.recv().is_err()); + }); + 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!(r.recv().is_err()); + }); + 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::<usize>(0); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::<Vec<_>>(); + + 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::<DropCounter>(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<dyn Any + Send>; + + let (s, r) = bounded::<T>(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::<Option<Receiver<T>>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} |