futures_ringbuf-0.4.0/.cargo_vcs_info.json0000644000000001360000000000100142460ustar { "git": { "sha1": "78ebf561ab1663455c19bab6a464b56a9d230a2b" }, "path_in_vcs": "" }futures_ringbuf-0.4.0/.github/PULL_REQUEST_TEMPLATE.md000064400000000000000000000003721046102023000202010ustar 00000000000000 futures_ringbuf-0.4.0/.github/funding.yml000064400000000000000000000000251046102023000165500ustar 00000000000000liberapay: najamelan futures_ringbuf-0.4.0/.github/workflows/ci.yml000064400000000000000000000031701046102023000175520ustar 00000000000000name: ci on : [push, pull_request] jobs: linux-stable: name: Linux Rust Stable runs-on: ubuntu-latest steps: - name: Install latest stable Rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true components: clippy - name: Checkout crate uses: actions/checkout@v3 - name: Run tests run: bash ci/test.bash linux-nightly: name: Linux Rust Nightly runs-on: ubuntu-latest steps: - name: Install latest nightly Rust uses: actions-rs/toolchain@v1 with: toolchain: nightly override: true components: clippy - name: Checkout crate uses: actions/checkout@v3 - name: Run clippy run : bash ci/clippy.bash - name: Build documentation run : bash ci/doc.bash - name: Run tests run : bash ci/test.bash - name: Install cargo-tarpaulin binary crate uses: actions-rs/install@v0.1 with: crate: cargo-tarpaulin version: latest use-tool-cache: true - name: Run cargo-tarpaulin run : | cargo tarpaulin --out Xml - name: Upload to codecov.io uses: codecov/codecov-action@v1.5.2 - name: install wasm-pack uses: jetli/wasm-pack-action@v0.3.0 with: # Optional version of wasm-pack to install(eg. 'v0.9.1', 'latest') version: 'latest' - name: Run tests on wasm run: bash ci/wasm.bash - name: Run cargo-deny uses: EmbarkStudios/cargo-deny-action@v1 futures_ringbuf-0.4.0/.gitignore000064400000000000000000000005001046102023000150210ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk futures_ringbuf-0.4.0/CHANGELOG.md000064400000000000000000000053271046102023000146560ustar 00000000000000# futures_ringbuf Changelog ## [Unreleased] [Unreleased]: https://github.com/najamelan/futures_ringbuf/compare/0.4...dev ## [0.4.0] [0.4.0]: https://github.com/najamelan/futures_ringbuf/compare/0.3.1...0.4.0 ### Added - **BREAKING CHANGE**: Update dependencies, including _ringbuf_ to version `0.3` and _tokio-util_ to version `0.7`. - `Dictator.seed` method to read the seed used on creation. ### Changed - Renamed `Dictator::seed` method to `new_seed`. ## [0.3.1] [0.3.1]: https://github.com/najamelan/futures_ringbuf/compare/0.3.0...0.3.1 ### Updated - CONTRIBUTING.md - external_doc gets removed in rustdoc 1.54. ### Fixed - Move CI to github actions ## [0.3.0] - 2020-11-03 [0.3.0]: https://github.com/najamelan/futures_ringbuf/compare/0.2.1...0.3.0 ## Removed - **BREAKING CHANGE**: Get rid of tokio version of traits in favor of `tokio_util::compat`. - **BREAKING CHANGE**: Get rid of feature flags. ## Added - `Sketchy`: A way to randomize behavior of network mocks. ## [0.2.1] - 2020-04-15 [0.2.1]: https://github.com/najamelan/futures_ringbuf/compare/0.2.0...0.2.1 ### Updated - Update to futures_codec 0.4. ### Fixed - fix docs to not break on stable. - fix CI configuration. ## [0.2.0] - 2019-01-15 [0.2.0]: https://github.com/najamelan/futures_ringbuf/compare/0.1.7...0.2.0 ### Added - Implement tokio AsyncRead/Write. This is behind a feature flag. ## [0.1.7] - 2019-11-12 [0.1.7]: https://github.com/najamelan/futures_ringbuf/compare/0.1.6...0.1.7 ### Updated - Update to ringbuf 0.2. ### Fixed - Fix a bug where a waker wasn't woken up in endpoint when the connection get's closed. ## [0.1.6] - 2019-11-12 [0.1.6]: https://github.com/najamelan/futures_ringbuf/compare/0.1.5...0.1.6 ### Updated - Update to futures 0.3. - Test on stable as well as nightly. ## [0.1.5] - 2019-10-10 [0.1.5]: https://github.com/najamelan/futures_ringbuf/compare/0.1.4...0.1.5 ### Added - Add Endpoint to mock full duplex connection. ## [0.1.4] - 2019-09-29 [0.1.4]: https://github.com/najamelan/futures_ringbuf/compare/0.1.3...0.1.4 ### Fixed - cleanup readme - fix wasm tests ## [0.1.3] - 2019-09-28 [0.1.3]: https://github.com/najamelan/futures_ringbuf/compare/0.1.2...0.1.3 ### Updated - update dependencies ### Fixed - fix docs.rs readme ## [0.1.2] - 2019-08-15 [0.1.2]: https://github.com/najamelan/futures_ringbuf/compare/0.1.1...0.1.2 ### Fixed - fix category slug that was lost in git history ## [0.1.1] - 2019-08-15 [0.1.1]: https://github.com/najamelan/futures_ringbuf/compare/0.1.0...0.1.1 ### Updated - test wasm support on CI - update dependencies that merged bug fixes since yesterday ## [0.1.0] - 2019-08-14 - initial release. futures_ringbuf-0.4.0/CONTRIBUTING.md000064400000000000000000000023561046102023000152750ustar 00000000000000# Contributing This repository accepts contributions. Ideas, questions, feature requests and bug reports can be filed through Github issues. Pull Requests are welcome on Github. By committing pull requests, you accept that your code might be modified and reformatted to fit the project coding style or to improve the implementation. Contributed code is considered licensed under the same license as the rest of the project unless explicitly agreed otherwise. See the `LICENCE` file. Please discuss what you want to see modified before filing a pull request if you don't want to be doing work that might be rejected. ## Code formatting I understand my code formatting style is quite uncommon, but it is deliberate and helps readability for me. Unfortunately, it cannot be achieved with automated tools like `rustfmt`. **Feel free to contribute code formatted however you are comfortable writing it**. I am happy to reformat during the review process. If you are uncomfortable reading my code, I suggest running `rustfmt` on the entire source tree or set your line-height to 1.2 instead of the common 1.5, which will make it look a lot less over the top. # git workflow Please file PR's against the `dev` branch, don't forget to update the documentation. futures_ringbuf-0.4.0/Cargo.lock0000644000000620700000000000100122260ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "assert_matches" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[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.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" 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.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" dependencies = [ "event-listener", ] [[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", "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 = "asynchronous-codec" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" dependencies = [ "bytes", "futures-sink", "futures-util", "memchr", "pin-project-lite", ] [[package]] name = "atomic-waker" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[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 = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[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 = "console_error_panic_hook" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ "cfg-if", "wasm-bindgen", ] [[package]] name = "crossbeam-utils" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] [[package]] name = "ctor" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", "syn 1.0.109", ] [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "ergo-pin" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bc1eb88aabef58f4b6ebfa4e5d644bf6e832a39a0fba225c120605580f4a30b" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "errno" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" 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 = "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.18", ] [[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-test" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84af27744870a4a325fa342ce65a940dfba08957b260b790ec278c1d81490349" dependencies = [ "futures-core", "futures-executor", "futures-io", "futures-macro", "futures-sink", "futures-task", "futures-util", "pin-project", "pin-utils", ] [[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 = "futures_ringbuf" version = "0.4.0" dependencies = [ "assert_matches", "async-std", "asynchronous-codec", "ergo-pin", "futures", "futures-test", "getrandom", "log", "pretty_assertions", "rand", "rand_chacha", "ringbuf", "rustc_version", "tokio", "tokio-util", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", ] [[package]] name = "getrandom" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[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 = "hermit-abi" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[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", "libc", "windows-sys", ] [[package]] name = "js-sys" version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" 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 = "libc" version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linux-raw-sys" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" dependencies = [ "value-bag", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "output_vt100" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ "winapi", ] [[package]] name = "parking" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" [[package]] name = "pin-project" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", "syn 2.0.18", ] [[package]] name = "pin-project-lite" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[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 = "pretty_assertions" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" dependencies = [ "ctor", "diff", "output_vt100", "yansi", ] [[package]] name = "proc-macro2" version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" 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 = "ringbuf" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79abed428d1fd2a128201cec72c5f6938e2da607c6f3745f769fabea399d950a" dependencies = [ "crossbeam-utils", ] [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "rustix" version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "scoped-tls" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "semver" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[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 = "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.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tokio" version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", "pin-project-lite", "windows-sys", ] [[package]] name = "tokio-util" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", "pin-project-lite", "tokio", "tracing", ] [[package]] name = "tracing" version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "value-bag" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e" [[package]] name = "waker-fn" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[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.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "wasm-bindgen-test" version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9e636f3a428ff62b3742ebc3c70e254dfe12b8c2b469d688ea59cdd4abcf502" dependencies = [ "console_error_panic_hook", "js-sys", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", ] [[package]] name = "wasm-bindgen-test-macro" version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18c1fad2f7c4958e7bcce014fa212f59a65d5e3721d0f77e6c0b27ede936ba3" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "web-sys" version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" 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-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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" 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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" futures_ringbuf-0.4.0/Cargo.toml0000644000000047620000000000100122550ustar # 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 = "futures_ringbuf" version = "0.4.0" authors = ["Naja Melan "] exclude = [ "ci", ".travis.yml", "TODO.md", ] description = "Mock Type implementing AsyncRead/AsyncWrite for testing and examples." documentation = "https://docs.rs/futures_ringbuf" readme = "README.md" keywords = [ "futures", "mocking", "stream", "testing", "async", ] categories = [ "asynchronous", "network-programming", "development-tools::testing", ] license = "Unlicense" repository = "https://github.com/najamelan/futures_ringbuf" resolver = "2" [package.metadata.docs.rs] all-features = true targets = [] [profile.release] codegen-units = 1 [dependencies.futures] version = "^0.3" [dependencies.log] version = "^0.4" [dependencies.rand] version = "^0.8" optional = true [dependencies.rand_chacha] version = "^0.3" optional = true [dependencies.ringbuf] version = "^0.3" [dev-dependencies.assert_matches] version = "^1" [dev-dependencies.async-std] version = "^1" features = ["attributes"] [dev-dependencies.asynchronous-codec] version = "^0.6" [dev-dependencies.ergo-pin] version = "^0.1" [dev-dependencies.futures-test] version = "^0.3" [dev-dependencies.pretty_assertions] version = "^1" [dev-dependencies.tokio] version = "^1" features = ["io-util"] [dev-dependencies.tokio-util] version = "^0.7" features = [ "codec", "compat", ] [build-dependencies.rustc_version] version = "^0.4" [features] default = [] sketchy = [ "rand", "rand_chacha", "getrandom", ] [target."cfg(target_arch = \"wasm32\")".dependencies.getrandom] version = "^0.2" features = ["js"] optional = true [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen] version = "^0.2" [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-futures] version = "^0.4" [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test] version = "^0.3" [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "najamelan/futures_ringbuf" futures_ringbuf-0.4.0/Cargo.toml.orig000064400000000000000000000036251046102023000157330ustar 00000000000000# Auto-generated from "Cargo.yml" [badges] [badges.maintenance] status = "actively-developed" [badges.travis-ci] repository = "najamelan/futures_ringbuf" [build-dependencies] rustc_version = "^0.4" [dependencies] futures = "^0.3" log = "^0.4" ringbuf = "^0.3" [dependencies.rand] optional = true version = "^0.8" [dependencies.rand_chacha] optional = true version = "^0.3" [dev-dependencies] assert_matches = "^1" asynchronous-codec = "^0.6" ergo-pin = "^0.1" futures-test = "^0.3" pretty_assertions = "^1" [dev-dependencies.async-std] features = ["attributes"] version = "^1" [dev-dependencies.tokio] features = ["io-util"] version = "^1" [dev-dependencies.tokio-util] features = ["codec", "compat"] version = "^0.7" [features] default = [] sketchy = ["rand", "rand_chacha", "getrandom"] [package] authors = ["Naja Melan "] categories = ["asynchronous", "network-programming", "development-tools::testing"] description = "Mock Type implementing AsyncRead/AsyncWrite for testing and examples." documentation = "https://docs.rs/futures_ringbuf" edition = "2018" exclude = ["ci", ".travis.yml", "TODO.md"] keywords = ["futures", "mocking", "stream", "testing", "async"] license = "Unlicense" name = "futures_ringbuf" readme = "README.md" repository = "https://github.com/najamelan/futures_ringbuf" resolver = "2" version = "0.4.0" [package.metadata] [package.metadata.docs] [package.metadata.docs.rs] all-features = true targets = [] [profile] [profile.release] codegen-units = 1 [target] [target."cfg(target_arch = \"wasm32\")"] [target."cfg(target_arch = \"wasm32\")".dependencies] [target."cfg(target_arch = \"wasm32\")".dependencies.getrandom] features = ["js"] optional = true version = "^0.2" [target."cfg(target_arch = \"wasm32\")".dev-dependencies] wasm-bindgen = "^0.2" wasm-bindgen-test = "^0.3" [target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-futures] version = "^0.4" futures_ringbuf-0.4.0/Cargo.yml000064400000000000000000000054121046102023000146160ustar 00000000000000package: # When releasing to crates.io: # # - last check for all TODO, FIXME, expect, unwrap. # - recheck log statements (informative, none left that were just for development, ...) # - `cargo +nightly doc` and re-read and final polish of documentation. # # - Update CHANGELOG.md. # - Update version numbers in Cargo.yml, Cargo.toml, install section of readme. # # - `touch **.rs && cargo clippy --tests --examples --benches --all-features` # - `cargo update` # - `cargo udeps --all-targets --all-features` # - `cargo audit` # - `cargo crev crate verify --show-all --recursive` and review. # - 'cargo test --all-targets --all-features' # # - push dev and verify CI result # - `cargo test` on dependent crates # # - cargo publish # - `git checkout master && git merge dev --no-ff` # - `git tag x.x.x` with version number. # - `git push && git push --tags` # version : 0.4.0 name : futures_ringbuf authors : [ Naja Melan ] description : Mock Type implementing AsyncRead/AsyncWrite for testing and examples. documentation : https://docs.rs/futures_ringbuf repository : https://github.com/najamelan/futures_ringbuf readme : README.md keywords : [ futures, mocking, stream, testing, async ] categories : [ asynchronous, network-programming, "development-tools::testing" ] license : Unlicense edition : '2018' resolver : '2' exclude : [ ci, .travis.yml, TODO.md ] metadata: docs: rs: all-features: true targets : [] features: default: [] # This enables the Sketchy and Dictator types. sketchy: [ rand, rand_chacha, getrandom ] badges: maintenance: { status : actively-developed } travis-ci : { repository : najamelan/futures_ringbuf } dependencies: # Public dependencies, bump major if changing any version number here. # ringbuf: ^0.3 futures: ^0.3 log : ^0.4 # private deps # rand : { version: ^0.8, optional: true } rand_chacha: { version: ^0.3, optional: true } dev-dependencies: pretty_assertions : ^1 futures-test : ^0.3 asynchronous-codec: ^0.6 assert_matches : ^1 ergo-pin : ^0.1 tokio : { version: ^1, features: [ io-util ] } tokio-util : { version: ^0.7, features: [ codec, compat ] } async-std : { version: ^1 , features: [ attributes ] } build-dependencies: rustc_version: ^0.4 profile: release: codegen-units: 1 target: 'cfg(target_arch = "wasm32")': dependencies: getrandom: { version: ^0.2, features: [ js ], optional: true } dev-dependencies: wasm-bindgen : ^0.2 wasm-bindgen-test : ^0.3 wasm-bindgen-futures : { version: ^0.4 } futures_ringbuf-0.4.0/LICENSE000064400000000000000000000022721046102023000140460ustar 00000000000000This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. 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 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. For more information, please refer to futures_ringbuf-0.4.0/README.md000064400000000000000000000172451046102023000143260ustar 00000000000000# futures_ringbuf [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) [![Build Status](https://api.travis-ci.org/najamelan/futures_ringbuf.svg?branch=master)](https://travis-ci.org/najamelan/futures_ringbuf) [![Docs](https://docs.rs/futures_ringbuf/badge.svg)](https://docs.rs/futures_ringbuf) [![crates.io](https://img.shields.io/crates/v/futures_ringbuf.svg)](https://crates.io/crates/futures_ringbuf) > A ringbuffer that implements AsyncRead/AsyncWrite. It can be used for testing async network crates cross-platform without having to make TCP connections. The crate provides a type `Endpoint` which allows creating both ends of a fake network stream with a ringbuffer in each direction. It facilitates testing more complex situations like back pressure. It can also be used as an in memory buffer for communicating between async tasks. I haven't done benchmarks yet. There are currently 2 versions of the AsyncRead/Write traits. The _futures-rs_ version and the _tokio_ version. This crate implements the futures version. You can get the tokio version by using [`tokio_util::compat`](https://docs.rs/tokio-util/latest/tokio_util/compat/index.html). Data in transit is held in an internal RingBuffer from the [ringbuf crate](https://crates.io/crates/ringbuf). When the `sketchy` feature is enabled, a type [`Sketchy`] is available that randomizes the behavior of the in memory buffers which would otherwise always be ready which isn't very realistic for testing code that will run against actual network connections later. This will randomly return pending and fill only partial buffers. ## Table of Contents - [Install](#install) - [Upgrade](#upgrade) - [Dependencies](#dependencies) - [Security](#security) - [Usage](#usage) - [WASM](#wasm) - [Basic Example](#basic-example) - [Endpoint Example](#endpoint-example) - [API](#api) - [Contributing](#contributing) - [Code of Conduct](#code-of-conduct) - [License](#license) ## Install With [cargo add](https://github.com/killercup/cargo-edit): `cargo add futures_ringbuf` With [cargo yaml](https://gitlab.com/storedbox/cargo-yaml): ```yaml dependencies: futures_ringbuf: ^0.4 ``` With raw Cargo.toml ```toml [dependencies] futures_ringbuf = "^0.4" ``` ### Upgrade Please check out the [changelog](https://github.com/najamelan/futures_ringbuf/blob/master/CHANGELOG.md) when upgrading. ### Dependencies This crate has few dependencies. Cargo will automatically handle its dependencies for you. ### Features The `sketchy` feature will turn on the `Sketchy` type which allows randomly changing the behavior of an async stream to enable testing situations that occur on an actual network like timing out, processing only partial buffers, pending, ... ## Security This crate uses `#![ forbid(unsafe_code) ]`, but it's dependencies use quite some unsafe. On first sight the unsafe usage in `ringbuf` looks sound, but I haven't scrutinized every detail of it and it's not documented. A lot of unsafe code is present in the futures library, which I haven't reviewed. ## Usage The crate provides a `RingBuffer` struct which implements `AsyncRead`/`AsyncWrite` from the futures library when `T` is u8. You can now call `split` provided by `AsyncRead` and treat them as both ends of a network connection. The reader will return `Poll::Pending` when the buffer is empty, and the writer when the buffer is full. They will wake each other up when new data/space is available. If you want to play with `std::io::Read`/`std::io::Write`, check out the `ringbuf` crate directly, as it's `Producer` and `Consumer` types implement these traits, so I didn't include them here. I haven't yet included `Stream`, `Sink`, because on `u8` that doesn't make much sense, but if there is demand, it can definitely be added. The requirements on `T` are `T: Sized + Copy`. If you want to seed the buffer before using it with futures_ringbuf, you can use the `Producer` and `Consumer` types of ringbuf. `futures_ringbuf::RingBuffer` implements `From< (Producer, Consumer) >`. ### WASM This crate works on WASM. See the [integration test](https://github.com/najamelan/futures_ringbuf/tree/master/test/wasm.rs) for some code. ### Basic example ```rust //! Frame a RingBuf with futures_codec. This example shows how the sending task will //! block when the buffer is full. When a reader consumes the buffer, the sender is woken up. //! //! Run with `cargo run --example basic`. // use { futures_ringbuf :: { * } , futures :: { SinkExt, StreamExt, executor::block_on, join } , asynchronous_codec :: { Framed, LinesCodec } , }; #[ async_std::main ] // async fn main() { let mock = RingBuffer::new( 13 ); let (mut writer, mut reader) = Framed::new( mock, LinesCodec{} ).split(); let send_task = async move { writer.send( "Hello World\n".to_string() ).await.expect( "send" ); println!( "sent first line" ); writer.send( "Second line\n".to_string() ).await.expect( "send" ); println!( "sent second line" ); writer.close().await.expect( "close sender" ); println!( "sink closed" ); }; let receive_task = async move { // If we would return here, the second line will never get sent // because the buffer is full. // // return; while let Some(msg) = reader.next().await.transpose().expect( "receive message" ) { println!( "Received: {:#?}", msg ); } }; // Poll them in concurrently // join!( send_task, receive_task ); } ``` ### Endpoint When using one ringbuffer, we get both ends of one connection. If we want a more realistic duplex connection, we need two ringbuffers, with one endpoint reading from the ringbuffer the other endpoint is writing to. Tasks need to be woken up correctly when new data or space becomes available... To facilitate this, an `Endpoint` type is provided which will take care of this setup for you. ### Endpoint example ```rust use { futures_ringbuf :: { * } , futures :: { AsyncWriteExt, AsyncReadExt, executor::block_on } , }; #[ async_std::main ] // async fn main() { // Buffer of 10 bytes in each direction. The buffer size always refers to the writing side, so here // the first 10 means the server can write 10 bytes before it's buffer is full. // When it's full it will return pending on writing and when it's empty it returns // pending on reading. // let (mut server, mut client) = Endpoint::pair( 10, 10 ); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; server.write( &data ).await.expect( "write" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); } ``` ## API API documentation can be found on [docs.rs](https://docs.rs/futures_ringbuf). ## Contributing Please check out the [contribution guidelines](https://github.com/najamelan/futures_ringbuf/blob/master/CONTRIBUTING.md). ### Testing `cargo test` On WASM, after [installing wasm-pack](https://rustwasm.github.io/wasm-pack/): `wasm-pack test --firefox --headless` or `wasm-pack test --chrome --headless` ### Code of conduct Any of the behaviors described in [point 4 "Unacceptable Behavior" of the Citizens Code of Conduct](http://citizencodeofconduct.org/#unacceptable-behavior) are not welcome here and might get you banned. If anyone including maintainers and moderators of the project fail to respect these/your limits, you are entitled to call them out. ## License [Unlicence](https://unlicense.org/) futures_ringbuf-0.4.0/build.rs000064400000000000000000000006701046102023000145060ustar 00000000000000// Detect the rustc channel // use rustc_version::{ version_meta, Channel }; fn main() { // Set cfg flags depending on release channel // match version_meta().unwrap().channel { Channel::Stable => println!( "cargo:rustc-cfg=stable" ), Channel::Beta => println!( "cargo:rustc-cfg=beta" ), Channel::Nightly => println!( "cargo:rustc-cfg=nightly" ), Channel::Dev => println!( "cargo:rustc-cfg=rustc_dev" ), } } futures_ringbuf-0.4.0/deny.toml000064400000000000000000000210601046102023000146710ustar 00000000000000# This template contains all of the possible sections and their default values # Note that all fields that take a lint level have these possible values: # * deny - An error will be produced and the check will fail # * warn - A warning will be produced, but the check will not fail # * allow - No warning or error will be produced, though in some cases a note # will be # The values provided in this template are the default values that will be used # when any section or field is not specified in your own configuration # If 1 or more target triples (and optionally, target_features) are specified, # only the specified targets will be checked when running `cargo deny check`. # This means, if a particular package is only ever used as a target specific # dependency, such as, for example, the `nix` crate only being used via the # `target_family = "unix"` configuration, that only having windows targets in # this list would mean the nix crate, as well as any of its exclusive # dependencies not shared by any other crates, would be ignored, as the target # list here is effectively saying which targets you are building for. targets = [ # The triple can be any string, but only the target triples built in to # rustc (as of 1.40) can be checked against actual config expressions #{ triple = "x86_64-unknown-linux-musl" }, # You can also specify which target_features you promise are enabled for a # particular target. target_features are currently not validated against # the actual valid features supported by the target architecture. #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, ] # This section is considered when running `cargo deny check advisories` # More documentation for the advisories section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html [advisories] # The path where the advisory database is cloned/fetched into db-path = "~/.cargo/advisory-db" # The url of the advisory database to use db-urls = [ "https://github.com/rustsec/advisory-db" ] # The lint level for security vulnerabilities vulnerability = "deny" # The lint level for unmaintained crates unmaintained = "warn" # The lint level for crates that have been yanked from their source registry yanked = "warn" # The lint level for crates with security notices. Note that as of # 2019-12-17 there are no security notice advisories in # https://github.com/rustsec/advisory-db notice = "warn" # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ #"RUSTSEC-0000-0000", ] # Threshold for security vulnerabilities, any vulnerability with a CVSS score # lower than the range specified will be ignored. Note that ignored advisories # will still output a note when they are encountered. # * None - CVSS Score 0.0 # * Low - CVSS Score 0.1 - 3.9 # * Medium - CVSS Score 4.0 - 6.9 # * High - CVSS Score 7.0 - 8.9 # * Critical - CVSS Score 9.0 - 10.0 #severity-threshold = # This section is considered when running `cargo deny check licenses` # More documentation for the licenses section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html [licenses] # The lint level for crates which do not have a detectable license unlicensed = "deny" # List of explictly allowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. allow = [ "MIT", "Apache-2.0", # "Apache-2.0 WITH LLVM-exception", "Unlicense", ] # List of explictly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. deny = [ #"Nokia", ] # Lint level for licenses considered copyleft copyleft = "allow" # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses # * both - The license will be approved if it is both OSI-approved *AND* FSF # * either - The license will be approved if it is either OSI-approved *OR* FSF # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF # * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved # * neither - This predicate is ignored and the default lint level is used allow-osi-fsf-free = "either" # Lint level used when no other predicates are matched # 1. License isn't in the allow or deny lists # 2. License isn't copyleft # 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" default = "deny" # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the # canonical license text of a valid SPDX license file. # [possible values: any between 0.0 and 1.0]. confidence-threshold = 0.8 # Allow 1 or more licenses on a per-crate basis, so that particular licenses # aren't accepted for every possible crate as with the normal allow list exceptions = [ # Each entry is the crate and version constraint, and its specific allow # list #{ allow = ["Zlib"], name = "adler32", version = "*" }, ] # Some crates don't have (easily) machine readable licensing information, # adding a clarification entry for it allows you to manually specify the # licensing information #[[licenses.clarify]] # The name of the crate the clarification applies to #name = "ring" # THe optional version constraint for the crate #version = "*" # The SPDX expression for the license requirements of the crate #expression = "MIT AND ISC AND OpenSSL" # One or more files in the crate's source used as the "source of truth" for # the license expression. If the contents match, the clarification will be used # when running the license check, otherwise the clarification will be ignored # and the crate will be checked normally, which may produce warnings or errors # depending on the rest of your configuration #license-files = [ # Each entry is a crate relative path, and the (opaque) hash of its contents #{ path = "LICENSE", hash = 0xbd0eed23 } #] [licenses.private] # If true, ignores workspace crates that aren't published, or are only # published to private registries ignore = false # One or more private registries that you might publish crates to, if a crate # is only published to private registries, and ignore is true, the crate will # not have its license(s) checked registries = [ #"https://sekretz.com/registry ] # This section is considered when running `cargo deny check bans`. # More documentation about the 'bans' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html [bans] # Lint level for when multiple versions of the same crate are detected multiple-versions = "warn" # The graph highlighting used when creating dotgraphs for crates # with multiple versions # * lowest-version - The path to the lowest versioned duplicate is highlighted # * simplest-path - The path to the version with the fewest edges is highlighted # * all - Both lowest-version and simplest-path are used highlight = "all" # List of crates that are allowed. Use with care! allow = [ #{ name = "ansi_term", version = "=0.11.0" }, ] # List of crates to deny deny = [ # Each entry the name of a crate and a version range. If version is # not specified, all versions will be matched. { name = "plutonium" }, # Crate intended to hide unsafe usage. { name = "fake-static" }, # Crate intended to demonstrate soundness bug in safe code. ] # Certain crates/versions that will be skipped when doing duplicate detection. skip = [ #{ name = "ansi_term", version = "=0.11.0" }, ] # Similarly to `skip` allows you to skip certain crates during duplicate # detection. Unlike skip, it also includes the entire tree of transitive # dependencies starting at the specified crate, up to a certain depth, which is # by default infinite skip-tree = [ #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, ] # This section is considered when running `cargo deny check sources`. # More documentation about the 'sources' section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html [sources] # Lint level for what to happen when a crate from a crate registry that is not # in the allow list is encountered unknown-registry = "warn" # Lint level for what to happen when a crate from a git repository that is not # in the allow list is encountered unknown-git = "warn" # List of URLs for allowed crate registries. Defaults to the crates.io index # if not specified. If it is specified but empty, no registries are allowed. allow-registry = ["https://github.com/rust-lang/crates.io-index"] # List of URLs for allowed Git repositories allow-git = [] futures_ringbuf-0.4.0/examples/basic.rs000064400000000000000000000023201046102023000163000ustar 00000000000000//! Frame a RingBuf with futures_codec. This example shows how the sending task will block when the buffer is full. //! When a reader consumes the buffer, the sender is woken up. //! //! Run with `cargo run --example basic`. // use { futures_ringbuf :: { * } , futures :: { SinkExt, StreamExt, join } , asynchronous_codec :: { Framed, LinesCodec } , }; #[async_std::main] // async fn main() { let mock = RingBuffer::new( 13 ); let (mut writer, mut reader) = Framed::new( mock, LinesCodec{} ).split(); let send_task = async move { writer.send( "Hello World\n".to_string() ).await.expect( "send" ); println!( "sent first line" ); writer.send( "Second line\n".to_string() ).await.expect( "send" ); println!( "sent second line" ); writer.close().await.expect( "close sender" ); println!( "sink closed" ); }; let receive_task = async move { // If we would return here, the second line will never get sent because the buffer is full. // // return; while let Some(msg) = reader.next().await.transpose().expect( "receive message" ) { println!( "Received: {:#?}", msg ); } }; // Poll them in concurrently // join!( send_task, receive_task ); } futures_ringbuf-0.4.0/examples/endpoint.rs000064400000000000000000000011561046102023000170450ustar 00000000000000use { futures_ringbuf :: { * } , futures :: { AsyncWriteExt, AsyncReadExt } , }; #[async_std::main] // async fn main() { // Buffer of 10 bytes in each direction. // When it's full it will return pending on writing and when it's empty it returns // pending on reading. // let (mut server, mut client) = Endpoint::pair( 10, 10 ); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; server.write_all( &data ).await.expect( "write" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); } futures_ringbuf-0.4.0/examples/tokio_endpoint.rs000064400000000000000000000017051046102023000202520ustar 00000000000000//! This example demonstrates how you can use tokio_util::compat to use the endpoint with //! code that uses the tokio AsyncRead and AsyncWrite as interface. //! use { futures_ringbuf :: { * } , tokio::io :: { AsyncWriteExt, AsyncReadExt } , tokio_util :: { compat::{ FuturesAsyncReadCompatExt } } , }; #[async_std::main] // async fn main() { // Buffer of 10 bytes in each direction. // When it's full it will return pending on writing and when it's empty it returns // pending on reading. // let (server, client) = Endpoint::pair( 10, 10 ); // This does all the magic. // let mut server = server.compat(); let mut client = client.compat(); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; server.write_all( &data ).await.expect( "write" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); } futures_ringbuf-0.4.0/src/async_read.rs000064400000000000000000000100441046102023000163020ustar 00000000000000use crate::{ import::*, RingBuffer }; impl AsyncRead for RingBuffer { /// Will return Poll::Pending when the buffer is empty. Will be woken up by the AsyncWrite impl when new /// data is written or the writer is closed. /// /// When the buffer (for network simulation) is closed and empty, or if you pass in a 0 byte buffer, /// this will return `Poll::Ready( Ok(0) )`. /// /// This method is infallible. // fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, dst: &mut [u8] ) -> Poll< Result > { if dst.is_empty() { return Poll::Ready( Ok(0) ); } let read = self.consumer.pop_slice( dst ); if read != 0 { // If a writer is waiting for place in the buffer, wake them. // if let Some(waker) = self.write_waker.take() { waker.wake(); } Poll::Ready( Ok(read) ) } else if self.closed { // Signals end of stream. // Ok(0).into() } else { // Store this waker so that the writer can wake us up after they wrote something. // self.read_waker.replace( cx.waker().clone() ); Poll::Pending } } } #[cfg(test)] // mod tests { // What's tested: // // ✔ reading from full // ✔ reading from half full // ✔ reading from empty buffer // ✔ setting the waker // ✔ the waker being woken up by a write // ✔ reading again after a write on the empty buffer // ✔ reading from a closed buffer // ✔ reading from a closed empty buffer // use crate::{ import::{ *, assert_eq }, RingBuffer }; #[test] // fn async_read() { block_on( async { let mut ring = RingBuffer::::new(2); // create a full buffer // ring.producer.push( b'a' ).expect( "write" ); ring.producer.push( b'b' ).expect( "write" ); // read 1 // let mut read_buf = [0u8;1]; AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap(); assert!( !ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 1 ); assert_eq!( ring.remaining(), 1 ); assert!( ring.read_waker .is_none() ); assert!( ring.write_waker.is_none() ); assert_eq!( b'a', read_buf[0] ); // read 2 // AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap(); assert!( ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 0 ); assert_eq!( ring.remaining(), 2 ); assert!( ring.read_waker .is_none() ); assert!( ring.write_waker.is_none() ); assert_eq!( b'b', read_buf[0] ); // read 3 // let (waker, count) = new_count_waker(); let mut cx = Context::from_waker( &waker ); assert!( AsyncRead::poll_read( Pin::new( &mut ring ), &mut cx, &mut read_buf ).is_pending() ); assert!( ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 0 ); assert_eq!( ring.remaining(), 2 ); assert!( ring.read_waker .is_some() ); assert!( ring.write_waker.is_none() ); // Write one back, verify read_waker get's woken up and we can read again // let arr = [ b'c' ]; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); assert!( !ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 1 ); assert_eq!( ring.remaining(), 1 ); assert!( ring.read_waker.is_none() ); assert_eq!( count, 1 ); assert_eq!( 1, AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap() ); assert_eq!( b'c', read_buf[0] ); assert!( ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 0 ); assert_eq!( ring.remaining(), 2 ); })} #[test] // fn closed_read() { block_on( async { let mut ring = RingBuffer::::new(2) ; let mut read_buf = [0u8;1] ; let arr = [ b'a' ] ; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); ring.close().await.unwrap(); AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap(); assert_eq!( b'a', read_buf[0] ); assert_eq!( AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap(), 0 ); // try read again, just in case // assert_eq!( AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap(), 0 ); })} } futures_ringbuf-0.4.0/src/async_write.rs000064400000000000000000000122421046102023000165230ustar 00000000000000use crate::{ import::*, RingBuffer }; impl AsyncWrite for RingBuffer { /// Will return Poll::Pending when the buffer is full. AsyncRead impl will wake up this task /// when new place is made. /// This method returns a `io::ErrorKind::NotConnected` error if called after `poll_close`. // fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, src: &[u8] ) -> Poll< Result > { if self.closed { return Err( io::ErrorKind::NotConnected.into() ).into() } let wrote = self.producer.push_slice( src ); if wrote != 0 { // If a reader is waiting for data, now that we wrote, wake them up. // if let Some(waker) = self.read_waker.take() { waker.wake(); } Ok(wrote).into() } else { // If the buffer is full, store our waker so readers can wake us up when they have consumed some data. // self.write_waker.replace( cx.waker().clone() ); Poll::Pending } } /// We are always flushed, this is a noop. /// This method is infallible. // fn poll_flush( self: Pin<&mut Self>, _cx: &mut Context<'_> ) -> Poll< Result<(), io::Error> > { Ok(()).into() } /// Closes the stream. After this no more data can be send into it. /// This method is infallible. // fn poll_close( mut self: Pin<&mut Self>, _cx: &mut Context<'_> ) -> Poll< Result<(), io::Error> > { self.closed = true; // If a reader is waiting for data, now that we wrote, wake them up. // if let Some(waker) = self.read_waker.take() { waker.wake(); } Ok(()).into() } } #[cfg(test)] // mod tests { // What's tested: // // ✔ writing to empty buffer // ✔ writing to half full // ✔ writing to full // ✔ setting the waker // ✔ the waker being woken up by a read // ✔ the waker from a reader is woken up when closing the writer // ✔ writing again after a read on the full buffer // ✔ writing to a closed buffer // use crate::{ import::{ *, assert_eq }, RingBuffer }; #[test] // fn async_write() { block_on( async { let mut ring = RingBuffer::::new(2); assert!( ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 0 ); assert_eq!( ring.remaining(), 2 ); assert!( ring.read_waker .is_none() ); assert!( ring.write_waker.is_none() ); // write 1 // let arr = [ b'a' ]; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); assert!( !ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 1 ); assert_eq!( ring.remaining(), 1 ); assert!( ring.read_waker .is_none() ); assert!( ring.write_waker.is_none() ); assert_eq!( b'a', ring.consumer.pop().unwrap() ); // write 2 // let arr = [ b'b' ]; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); let arr = [ b'c' ]; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); assert!( !ring.is_empty() ); assert!( ring.is_full() ); assert_eq!( ring.len() , 2 ); assert_eq!( ring.remaining(), 0 ); assert!( ring.read_waker .is_none() ); assert!( ring.write_waker.is_none() ); assert_eq!( b'b', ring.consumer.pop().unwrap() ); assert_eq!( b'c', ring.consumer.pop().unwrap() ); // write 3 // let arr = [ b'd' ]; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); let arr = [ b'e' ]; AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); let (waker, count) = new_count_waker(); let mut cx = Context::from_waker( &waker ); let arr = [ b'f' ]; assert!( AsyncWrite::poll_write( Pin::new( &mut ring ), &mut cx, &arr ).is_pending() ); assert!( !ring.is_empty() ); assert!( ring.is_full() ); assert_eq!( ring.len() , 2 ); assert_eq!( ring.remaining(), 0 ); assert!( ring.write_waker.is_some() ); // Pop 1 and try writing again // let mut read_buf = [0u8;1]; assert_eq!( 1, AsyncReadExt::read( &mut ring, &mut read_buf ).await.unwrap() ); assert_eq!( b'd', read_buf[0] ); assert!( ring.write_waker.is_none() ); assert_eq!( count, 1 ); assert!( !ring.is_empty() ); assert!( !ring.is_full() ); assert_eq!( ring.len() , 1 ); assert_eq!( ring.remaining(), 1 ); AsyncWriteExt::write( &mut ring, &arr ).await.expect( "write" ); assert!( !ring.is_empty() ); assert!( ring.is_full() ); assert_eq!( ring.len() , 2 ); assert_eq!( ring.remaining(), 0 ); })} #[test] // fn close_wake_reader() { block_on( async { let mut ring = RingBuffer::::new(2); let (waker, _count) = new_count_waker(); let mut cx = Context::from_waker( &waker ); let mut read_buf = [0u8;1]; assert!( AsyncRead::poll_read( Pin::new( &mut ring ), &mut cx, &mut read_buf ).is_pending() ); assert!( ring.read_waker .is_some() ); assert!( ring.write_waker.is_none() ); ring.close().await.expect( "close" ); assert!( ring.read_waker.is_none() ); })} #[test] // fn closed_write() { block_on( async { let mut ring = RingBuffer::::new(2); ring.close().await.unwrap(); let arr = [ b'a' ]; assert_eq!( AsyncWriteExt::write( &mut ring, &arr ).await.unwrap_err().kind(), io::ErrorKind::NotConnected ); // Should be the same // assert_eq!( AsyncWriteExt::write( &mut ring, &arr ).await.unwrap_err().kind(), io::ErrorKind::NotConnected ); })} } futures_ringbuf-0.4.0/src/dictator.rs000064400000000000000000000052011046102023000160020ustar 00000000000000use { rand :: { Rng, RngCore, thread_rng, SeedableRng, distributions::uniform::SampleUniform } , rand_chacha :: { ChaCha8Rng } , std :: { ops::Range, fmt } , log :: { * } , }; /// Dictator that makes random decisions based on a seed. That is the decisions are /// reproducible. For reproducible decisions, your use of the dictator must be deterministic. // #[ derive( Debug ) ] // pub struct Dictator { seed: u64, rng : ChaCha8Rng, } impl Dictator { /// Birth place of all dictators. This method will log the seed with log::trace. /// Make sure you turn on logging for the futures_ringbuf crate so you can reproduce failing tests. // pub fn new( seed: u64 ) -> Self { trace!( "Creating new dictator with seed {}", seed ); Self { seed, rng: ChaCha8Rng::seed_from_u64( seed ), } } /// Ask the dictator permission to do something. // pub fn please( &mut self, question: &str, prob: f64 ) -> bool { let answer = self.rng.gen_bool( prob ); trace!( "dictator please {}, answer: {}", question, answer ); answer } /// Ask the dictator to pick from a range of values. // pub fn pick( &mut self, what: &str, range: Range ) -> Idx { let pick = self.rng.gen_range( range.clone() ); trace!( "dictator pick {} from {:?}, answer: {:?}", what, range, pick ); pick } /// Return the seed used when creating this Dictator. // pub fn seed(&self) -> u64 { self.seed } /// Create a new random seed from entropy. // pub fn new_seed() -> u64 { thread_rng().next_u64() } } #[ cfg(test) ] // mod tests { use super::*; #[test] // fn predictable() { let seed = 265468510; let mut bd = Dictator::new( seed ); assert!( !bd.please( "one" , 0.4 ) ); assert!( !bd.please( "two" , 0.6 ) ); assert!( !bd.please( "three", 0.5 ) ); assert!( !bd.please( "four" , 0.3 ) ); assert!( bd.please( "five" , 0.9 ) ); assert!( !bd.please( "six" , 0.2 ) ); assert!( !bd.please( "seven", 0.5 ) ); assert!( bd.please( "eight", 0.4 ) ); assert_eq!( 1 , bd.pick( "nine" , 0..100 ) ); assert_eq!( 94, bd.pick( "ten" , 0..100 ) ); assert_eq!( 46, bd.pick( "eleven", 0..100 ) ); assert!( bd.please( "twelve" , 0.6 ) ); assert!( bd.please( "thirteen", 0.5 ) ); assert!( bd.please( "fourteen", 0.5 ) ); assert!( bd.please( "fifteen" , 0.5 ) ); assert!( !bd.please( "sixteen" , 0.5 ) ); assert_eq!( seed, bd.seed() ); } } futures_ringbuf-0.4.0/src/endpoint.rs000064400000000000000000000063141046102023000160170ustar 00000000000000use crate::{ import::*, RingBuffer }; /// Represents a network endpoint. This is for duplex connection mocking. Each direction has a separate /// ringbuffer and one buffer's readhalf is connected to the other buffer's writehalf in order to simulate /// a duplex connection. /// /// The main way to create this is to call `Endpoint::pair` which returns a tuple of endpoints, and which /// let's you specify the buffer size for each direction. /// /// Endpoint implements AsyncRead/AsyncWrite so you can feed it to interfaces that need those combined in /// a single type. /// /// By setting the buffer size precisely, one can simulate back pressure. Endpoint will return Pending on writes /// when full and on reads when empty. /// /// When calling close on an endpoint, any further writes on that endpoint will return [`std::io::ErrorKind::NotConnected`] /// and any reads on the other endpoint will continue to empty the buffer and then return `Ok(0)`. `Ok(0)` means /// no new data will ever appear, unless you passed in a zero sized buffer. /// /// If the remote endpoint is pending on a read, the task will be woken up when calling `close` or dropping /// this endpoint. // #[ derive( Debug ) ] // pub struct Endpoint { writer: WriteHalf< RingBuffer >, reader: ReadHalf < RingBuffer >, } impl Endpoint { /// Create a pair of endpoints, specifying the buffer size for each one. The buffer size corresponds /// to the buffer the respective endpoint writes to. The other will read from this one. // pub fn pair( a_buf: usize, b_buf: usize ) -> (Endpoint, Endpoint) { let ab_buf = RingBuffer::::new( a_buf ); let ba_buf = RingBuffer::::new( b_buf ); let (ab_reader, ab_writer) = ab_buf.split(); let (ba_reader, ba_writer) = ba_buf.split(); ( Endpoint{ writer: ab_writer, reader: ba_reader }, Endpoint{ writer: ba_writer, reader: ab_reader }, ) } } impl AsyncRead for Endpoint { fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8] ) -> Poll< io::Result > { let poll = Pin::new(&mut self.reader).poll_read(cx, buf); log::trace!("poll_read() => {:?}", poll); poll } } impl AsyncWrite for Endpoint { fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8] ) -> Poll< io::Result > { let poll = Pin::new(&mut self.writer).poll_write(cx, buf); log::trace!("poll_write() => {:?}", poll); poll } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll< io::Result<()> > { let poll = Pin::new(&mut self.writer).poll_flush(cx); log::trace!("poll_flush() => {:?}", poll); poll } fn poll_close( mut self: Pin<&mut Self>, cx: &mut Context<'_> ) -> Poll< io::Result<()> > { let poll = Pin::new(&mut self.writer).poll_close(cx); log::trace!("poll_close() => {:?}", poll); poll } } /// Makes sure that the reader of the other end is notified (woken up if pending) of the connection closure. // impl Drop for Endpoint { fn drop( &mut self ) { // Closing the ringbuffer is not an async operation. It always returns immediately, // so we just ignore the return value of poll_close. // let waker = noop_waker(); let mut cx = Context::from_waker( &waker ); let _ = Pin::new( self ).poll_close( &mut cx); } } futures_ringbuf-0.4.0/src/lib.rs000064400000000000000000000033211046102023000147400ustar 00000000000000#![ cfg_attr( nightly, feature(doc_cfg) ) ] #![ doc = include_str!("../README.md") ] #![ doc ( html_root_url = "https://docs.rs/futures_ringbuf" ) ] #![ deny ( missing_docs ) ] #![ forbid ( unsafe_code ) ] #![ allow ( clippy::suspicious_else_formatting ) ] #![ warn ( missing_debug_implementations , nonstandard_style , rust_2018_idioms , trivial_casts , trivial_numeric_casts , unused_extern_crates , unused_qualifications , single_use_lifetimes , unreachable_pub , variant_size_differences , )] mod ring_buffer ; pub use self::ring_buffer::* ; mod async_read ; mod async_write ; mod endpoint ; pub use endpoint::*; #[ cfg( feature = "sketchy" ) ] mod dictator ; #[ cfg( feature = "sketchy" ) ] mod sketchy ; #[ cfg( feature = "sketchy" ) ] pub use dictator::* ; #[ cfg( feature = "sketchy" ) ] pub use sketchy::* ; // External dependencies // mod import { pub(crate) use { std :: { fmt, task::Waker } , ringbuf :: { HeapRb as SyncRingBuffer } , futures :: { AsyncRead, AsyncWrite, AsyncReadExt } , futures::io :: { ReadHalf, WriteHalf } , futures :: { task::noop_waker } , std :: { io, pin::Pin, task::{ Context, Poll } } , }; #[ cfg(test) ] // pub(crate) use { futures :: { AsyncWriteExt } , pretty_assertions :: { assert_eq } , futures :: { executor::block_on } , futures_test :: { task::{ new_count_waker } } , }; } futures_ringbuf-0.4.0/src/ring_buffer.rs000064400000000000000000000060571046102023000164730ustar 00000000000000use crate::import::*; type Producer = ringbuf::HeapProducer; type Consumer = ringbuf::HeapConsumer; /// A RingBuffer that implements `AsyncRead` and `AsyncWrite` from the futures library. /// /// This object is rather special in that it's read and writes are connected to a single /// ringbuffer. It's good for low level unit tests for (eg. framing a connection with a /// codec) and verifying that a codec writes the correct data, but it does not mock a full /// network connection. Subtle things can go wrong, like when using `AsyncRead::split` and /// dropping the `WriteHalf`, the `ReadHalf` cannot detect that and the task won't be woken up. /// /// If you want to mock a network connection, use [Endpoint](crate::Endpoint). // #[ allow( dead_code )] // pub struct RingBuffer { pub(crate) producer : Producer , pub(crate) consumer : Consumer , pub(crate) read_waker : Option , pub(crate) write_waker: Option , pub(crate) closed : bool , } impl RingBuffer { /// Create a new RingBuffer with a defined capacity. Note that `capacity != length`, similar /// to Vec. // pub fn new( size: usize ) -> Self { let (producer, consumer) = SyncRingBuffer::new( size ).split(); Self { producer , consumer , read_waker : None , write_waker : None , closed : false , } } /// The total capacity of the buffer // pub fn capacity( &self ) -> usize { self.producer.capacity() } /// Whether there is no data at all in the buffer. // pub fn is_empty( &self ) -> bool { self.producer.is_empty() } /// Whether the buffer is completely full. // pub fn is_full(&self) -> bool { self.producer.is_full() } /// The length of the data in the buffer. // pub fn len(&self) -> usize { self.producer.len() } /// How much free space there is left in the container. On empty, `remaining == capacity` // pub fn remaining(&self) -> usize { self.producer.free_len() } } /// The compiler cannot verify that the producer/consumer are from the same `RingBuffer` object. /// Obviously if you abuse this things won't work as expected. /// /// I added this so you can seed a buffer before passing it to futures_ringbuf. // impl From< (Producer, Consumer) > for RingBuffer { fn from( buffer: (Producer, Consumer) ) -> Self { let (producer, consumer) = (buffer.0, buffer.1); Self { producer , consumer , read_waker : None , write_waker : None , closed : false , } } } impl From< SyncRingBuffer > for RingBuffer { fn from( buffer: SyncRingBuffer ) -> Self { let (producer, consumer) = buffer.split(); Self { producer , consumer , read_waker : None , write_waker : None , closed : false , } } } impl fmt::Debug for RingBuffer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "RingBuffer with capacity: {}", self.capacity() ) } } futures_ringbuf-0.4.0/src/sketchy.rs000064400000000000000000000105161046102023000156500ustar 00000000000000use crate::{ import::*, Dictator }; /// A wrapper for any type that implements `AsyncRead`/`AsyncWrite`, that will randomly return pending and /// reschedule or only process partial buffers. This helps with testing consumers of these interfaces /// on in memory objects like a mock network connection created with [Endpoint](crate::Endpoint) which /// would otherwise always be ready. This simulates a more random behavior you might observe on a real /// network connection. /// /// The randomness is based on a seed, so that you can reproduce failing tests. In order be reproducible, /// your test should be deterministic. In general avoid spawning and executor schedulers, prefer `join!` /// from the futures library to run parts of your test concurrently. /// /// # Example /// /// ``` /// #[test] /// // /// fn my_test() /// { /// // Make sure to log for failing tests, so you can rerun with the same seed. /// // futures-ringbuf will log any decisions made by `Sketchy` and will log the /// // seed. /// // /// let _ = flexi_logger::Logger::with_str( "trace" ).start(); /// /// // Since we want to test a random combination of events (pending, partial buffer fills, normal behavior) /// // let's run this several times. /// // /// for _ in 0..500 /// { /// let seed = Dictator::seed(); /// let (server, client) = Endpoint::pair( 64, 64 ); /// let server = Sketchy::new( server, seed ); /// let client = Sketchy::new( client, seed ); /// /// /// // now use AsyncRead/AsyncWrite on server and client to test your code, /// // eg. a codec implementation. /// } /// } /// ``` // #[ derive( Debug ) ] // pub struct Sketchy { inner: T , bd : Dictator , } impl Sketchy { /// Create a new wrapper with random behavior based on seed. // pub fn new( inner: T, seed: u64 ) -> Self { Self { inner, bd: Dictator::new( seed ) } } } impl AsyncRead for Sketchy where T: AsyncRead + Unpin { /// About one third of the time, this will return pending and reschedule the waker, one third will /// only pass a partial buffer to the wrapped type and one third will just forward the call unmodified. // fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8] ) -> Poll< Result > { if self.bd.please( "AsyncRead::poll_read - return Pending?", 0.3 ) { cx.waker().wake_by_ref(); return Poll::Pending; } // Buffer 0 is an error from the caller and buffer 1 means we are not allowed to make it 0, // so no point in running this part. // if buf.len() > 1 && self.bd.please( "AsyncRead::poll_read - return Partial?", 0.5 ) { // It's important we don't allow zero here, since that usually means that the stream has ended. // let size = self.bd.pick( "AsyncRead::poll_read - buffer size", 1..buf.len() ); return Pin::new( &mut self.inner ).poll_read( cx, &mut buf[0..size] ) } Pin::new( &mut self.inner ).poll_read( cx, buf ) } } impl AsyncWrite for Sketchy where T: AsyncWrite + Unpin { fn poll_write( mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8] ) -> Poll< io::Result > { if self.bd.please( "AsyncWrite::poll_write - return Pending?", 0.3 ) { cx.waker().wake_by_ref(); return Poll::Pending; } // Buffer 0 is an error from the caller and buffer 1 means we are not allowed to make it 0, // so no point in running this part. // if buf.len() > 1 && self.bd.please( "AsyncWrite::poll_write - return Partial?", 0.5 ) { // It's important we don't allow zero here, since that usually means that the stream has ended. // let size = self.bd.pick( "AsyncWrite::poll_write - buffer size", 1..buf.len() ); return Pin::new( &mut self.inner ).poll_write( cx, &buf[0..size] ) } Pin::new( &mut self.inner ).poll_write( cx, buf ) } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll< io::Result<()> > { if self.bd.please( "AsyncWrite::poll_flush - return Pending?", 0.5 ) { cx.waker().wake_by_ref(); return Poll::Pending; } Pin::new( &mut self.inner ).poll_flush( cx ) } fn poll_close( mut self: Pin<&mut Self>, cx: &mut Context<'_> ) -> Poll< io::Result<()> > { if self.bd.please( "AsyncWrite::poll_close - return Pending?", 0.5 ) { cx.waker().wake_by_ref(); return Poll::Pending; } Pin::new( &mut self.inner ).poll_close( cx ) } } futures_ringbuf-0.4.0/tests/endpoint.rs000064400000000000000000000110311046102023000163620ustar 00000000000000// Tested: // // ✔ basic sending and receiving // ✔ try to read after close // ✔ try to write after close // ✔ read remaining data after close // ✔ wake up pending reader after call to close // - wake up pending reader after drop (requires an async drop) // use { futures_ringbuf :: { * } , asynchronous_codec :: { Framed, LinesCodec } , futures :: { AsyncRead, AsyncWrite, AsyncWriteExt, AsyncReadExt, executor::block_on } , futures :: { future::join, SinkExt, StreamExt, channel::oneshot } , futures_test :: { task::noop_waker } , assert_matches :: { assert_matches } , std :: { task::{ Poll, Context } } , ergo_pin :: { ergo_pin } , }; #[ test ] // fn basic_usage() { block_on( async { let (mut server, mut client) = Endpoint::pair( 10, 10 ); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; server.write_all( &data ).await.expect( "write" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); })} #[ test ] #[ ergo_pin ] // fn close_write() { let (server, _client) = Endpoint::pair( 10, 10 ); let waker = noop_waker(); let mut cx = Context::from_waker( &waker ); let mut pserv = pin!( server ); let res = pserv.as_mut().poll_close( &mut cx ); assert_matches!( res, Poll::Ready( Ok(_) ) ); let buf = vec![ 1,2,3 ]; let res = pserv.poll_write( &mut cx, &buf ); match res { Poll::Ready( Err(e) ) => assert_eq!( e.kind(), std::io::ErrorKind::NotConnected ) , _ => panic!( "poll_write should return error: {:?}", res ), } } #[ test ] #[ ergo_pin ] // fn close_read() { // flexi_logger::Logger::with_str( "futures_ringbuf=trace" ).start().expect( "flexi_logger"); let (server, client) = Endpoint::pair( 10, 10 ); let mut pserv = pin!( server ); let pcl = pin!( client ); let waker = noop_waker(); let mut cx = Context::from_waker( &waker ); // let res = pserv.as_mut().poll_close( &mut cx ); // assert_matches!( res, Poll::Ready( Ok(_) ) ); block_on( pserv.as_mut().close() ).expect( "close server" ); let mut buf = [0u8;10]; let res = pcl.poll_read( &mut cx, &mut buf ); assert_matches!( res, Poll::Ready( Ok(0) )); } #[ test ] // fn close_read_remaining() { block_on( async { let (mut server, mut client) = Endpoint::pair( 10, 10 ); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; let mut read2 = [0u8;3]; server.write_all( &data ).await.expect( "write" ); server.close().await.expect( "close" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); let n = client.read( &mut read2 ).await.expect( "read" ); assert_eq!( n , 0 ); assert_eq!( read2, [0u8;3] ); })} #[ test ] // fn close_wake_pending() { let (server, client) = Endpoint::pair( 10, 10 ); let (sender, receiver) = oneshot::channel::<()>(); let svr = async move { let (mut sink, _stream) = Framed::new( server, LinesCodec{} ).split(); receiver.await.expect( "read channel" ); sink.close().await.expect( "close" ); }; let clt = async move { let (_sink, mut stream) = Framed::new( client, LinesCodec{} ).split(); sender.send(()).expect( "write channel" ); // This should not hang // assert!( stream.next().await.is_none() ); }; // WARNING: even though we synchronize with the oneshot channel, this test does not hang // when it should if the order of clt and svr are reversed here. // block_on( join( clt, svr ) ); } #[ test ] // fn drop_wake_pending() { let (server, mut client) = Endpoint::pair( 10, 10 ); let (sender, receiver) = oneshot::channel::<()>(); let svr = async move { receiver.await.expect( "read channel" ); drop( server ); }; let clt = async move { sender.send(()).expect( "write channel" ); let mut read_buf = [0u8;1]; // This should not hang // let result = client.read( &mut read_buf ).await.expect( "Ok(0)" ); assert_eq!( result, 0 ); }; // WARNING: even though we synchronize with the oneshot channel, this test does not hang // when it should if the order of clt and svr are reversed here. // block_on( join( clt, svr ) ); } futures_ringbuf-0.4.0/tests/endpoint_tokio.rs000064400000000000000000000120311046102023000175700ustar 00000000000000// Tested: // // ✔ basic sending and receiving // ✔ try to read after close // ✔ try to write after close // ✔ read remaining data after close // ✔ wake up pending reader after call to close // - wake up pending reader after drop (requires an async drop) // use { futures_ringbuf :: { * } , tokio_util :: { codec::{ Framed, LinesCodec }, compat::{ FuturesAsyncReadCompatExt } } , tokio::io :: { AsyncRead, AsyncWrite, AsyncWriteExt, AsyncReadExt, ReadBuf } , futures :: { future::join, SinkExt, StreamExt, channel::oneshot, executor::block_on } , futures_test :: { task::noop_waker } , assert_matches :: { assert_matches } , std :: { task::{ Poll, Context } } , ergo_pin :: { ergo_pin } , }; #[ test ] // fn basic_usage() { block_on( async { let (server, client) = Endpoint::pair( 10, 10 ); let mut server = server.compat(); let mut client = client.compat(); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; server.write_all( &data ).await.expect( "write" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); })} #[ test ] #[ ergo_pin ] // fn close_write() { let (server, client) = Endpoint::pair( 10, 10 ); let server = server.compat(); let _client = client.compat(); let waker = noop_waker(); let mut cx = Context::from_waker( &waker ); let mut pserv = pin!( server ); let res = pserv.as_mut().poll_shutdown( &mut cx ); assert_matches!( res, Poll::Ready( Ok(_) ) ); let buf = vec![ 1,2,3 ]; let res = pserv.poll_write( &mut cx, &buf ); match res { Poll::Ready( Err(e) ) => assert_eq!( e.kind(), std::io::ErrorKind::NotConnected ) , _ => panic!( "poll_write should return error: {:?}", res ), } } #[ test ] #[ ergo_pin ] // fn close_read() { // flexi_logger::Logger::with_str( "futures_ringbuf=trace" ).start().expect( "flexi_logger"); let (server, client) = Endpoint::pair( 10, 10 ); let server = server.compat(); let client = client.compat(); let mut pserv = pin!( server ); let pcl = pin!( client ); let waker = noop_waker(); let mut cx = Context::from_waker( &waker ); // let res = pserv.as_mut().poll_close( &mut cx ); // assert_matches!( res, Poll::Ready( Ok(_) ) ); block_on( pserv.as_mut().shutdown() ).expect( "close server" ); let mut buf = [0u8;10]; let mut read_buf = ReadBuf::new( &mut buf ); let res = pcl.poll_read( &mut cx, &mut read_buf ); assert_eq!( read_buf.filled().len(), 0 ); assert_matches!( res, Poll::Ready( Ok(()) )); } #[ test ] // fn close_read_remaining() { block_on( async { let (server, client) = Endpoint::pair( 10, 10 ); let mut server = server.compat(); let mut client = client.compat(); let data = vec![ 1,2,3 ]; let mut read = [0u8;3]; let mut read2 = [0u8;3]; server.write_all( &data ).await.expect( "write" ); server.shutdown().await.expect( "close" ); let n = client.read( &mut read ).await.expect( "read" ); assert_eq!( n , 3 ); assert_eq!( read, vec![ 1,2,3 ][..] ); let n = client.read( &mut read2 ).await.expect( "read" ); assert_eq!( n , 0 ); assert_eq!( read2, [0u8;3] ); })} #[ test ] // fn close_wake_pending() { let (server, client) = Endpoint::pair( 10, 10 ); let server = server.compat(); let client = client.compat(); let (sender, receiver) = oneshot::channel::<()>(); let svr = async move { let (mut sink, _stream) = Framed::new( server, LinesCodec::new() ).split::(); receiver.await.expect( "read channel" ); sink.close().await.expect( "close" ); }; let clt = async move { let (_sink, mut stream) = Framed::new( client, LinesCodec::new() ).split::(); sender.send(()).expect( "write channel" ); // This should not hang // assert!( stream.next().await.is_none() ); }; // WARNING: even though we synchronize with the oneshot channel, this test does not hang // when it should if the order of clt and svr are reversed here. // block_on( join( clt, svr ) ); } #[ test ] // fn drop_wake_pending() { let (server, client) = Endpoint::pair( 10, 10 ); let server = server.compat(); let mut client = client.compat(); let (sender, receiver) = oneshot::channel::<()>(); let svr = async move { receiver.await.expect( "read channel" ); drop( server ); }; let clt = async move { sender.send(()).expect( "write channel" ); let mut read_buf = [0u8;1]; // This should not hang // let result = client.read( &mut read_buf ).await.expect( "Ok(0)" ); assert_eq!( result, 0 ); }; // WARNING: even though we synchronize with the oneshot channel, this test does not hang // when it should if the order of clt and svr are reversed here. // block_on( join( clt, svr ) ); } futures_ringbuf-0.4.0/tests/wasm.rs000064400000000000000000000021051046102023000155130ustar 00000000000000#![ cfg( target_arch="wasm32" ) ] // Verify basic functionality on wasm // // Tested: // // ✔ the code from the basic example // use { wasm_bindgen_test :: { * } , wasm_bindgen_futures :: { spawn_local } , futures_ringbuf :: { * } , futures :: { SinkExt, StreamExt, future::ready } , asynchronous_codec :: { Framed, LinesCodec } , }; wasm_bindgen_test_configure!(run_in_browser); #[wasm_bindgen_test] // fn basic_example() { let mock = RingBuffer::new( 13 ); let (mut writer, reader) = Framed::new( mock, LinesCodec{} ).split(); let send_task = async move { writer.send( "Hello World\n".to_string() ).await.expect( "send" ); writer.send( "Second line\n".to_string() ).await.expect( "send" ); writer.close().await.expect( "close sender" ); }; let receive_task = async move { let count = reader.fold( 0, |count, _| ready( count + 1 ) ).await; assert_eq!( count, 2 ); }; spawn_local( send_task ); spawn_local( receive_task ); } futures_ringbuf-0.4.0/tests/wasm_tokio.rs000064400000000000000000000024071046102023000167250ustar 00000000000000#![ cfg( target_arch="wasm32" ) ] // Verify basic functionality on wasm // // Tested: // // ✔ the code from the basic example // use { wasm_bindgen_test :: { * } , wasm_bindgen_futures :: { spawn_local } , futures_ringbuf :: { * } , futures :: { SinkExt, StreamExt, future::ready } , tokio_util :: { codec::{ Framed, LinesCodec }, compat::{ FuturesAsyncReadCompatExt } } , }; wasm_bindgen_test_configure!(run_in_browser); #[wasm_bindgen_test] // fn basic_example_tokio() { let mock = RingBuffer::new( 13 ).compat(); let (mut writer, reader) = Framed::new( mock, LinesCodec::new() ).split(); let send_task = async move { writer.send( "Hello World.".to_string() ).await.expect( "send" ); writer.send( "Second line.".to_string() ).await.expect( "send" ); writer.close().await.expect( "close sender" ); }; let receive_task = async move { let count = reader.fold( 0, |count, _| ready( count + 1 ) ).await; assert_eq!( count, 2 ); }; spawn_local( send_task ); spawn_local( receive_task ); }