maybe-async-0.2.7/.cargo_vcs_info.json0000644000000001360000000000100132520ustar { "git": { "sha1": "b8be6e43d3f64bae52063d5b46f4e627303bc733" }, "path_in_vcs": "" }maybe-async-0.2.7/.github/dependabot.yml000064400000000000000000000003211046102023000162260ustar 00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily time: "21:00" open-pull-requests-limit: 10 ignore: - dependency-name: tokio versions: - 0.2.25 maybe-async-0.2.7/.github/workflows/linux.yml000064400000000000000000000035141046102023000173240ustar 00000000000000name: CI (Linux) on: [push, pull_request] jobs: build_and_test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: rustfmt uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check - name: check build (async) uses: actions-rs/cargo@v1 with: command: check args: --all --bins --examples --tests - name: tests (async) uses: actions-rs/cargo@v1 timeout-minutes: 40 with: command: test args: --all --no-fail-fast -- --nocapture - name: check build (is_sync) uses: actions-rs/cargo@v1 with: command: check args: --features=is_sync --all --bins --examples --tests - name: tests (is_sync) uses: actions-rs/cargo@v1 timeout-minutes: 40 with: command: test args: --features=is_sync --all --no-fail-fast -- --nocapture doc: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: doc (async) uses: actions-rs/cargo@v1 env: RUSTDOCFLAGS: -Dwarnings with: command: doc args: --all --no-deps - name: doc (is_sync) uses: actions-rs/cargo@v1 env: RUSTDOCFLAGS: -Dwarnings with: command: doc args: --all --no-deps --features=is_sync publish: name: Publish Package needs: build_and_test if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: login env: SUPER_SECRET: ${{ secrets.CARGO_TOKEN }} run: cargo login "$SUPER_SECRET" shell: bash - name: publish uses: actions-rs/cargo@v1 with: command: publish maybe-async-0.2.7/.gitignore000064400000000000000000000000621046102023000140300ustar 00000000000000/target **/*.rs.bk Cargo.lock .idea/** .vscode/**maybe-async-0.2.7/.rustfmt.toml000064400000000000000000000002311046102023000145150ustar 00000000000000reorder_imports = true format_code_in_doc_comments = true normalize_doc_attributes = true wrap_comments = true format_strings = true merge_imports = truemaybe-async-0.2.7/.standard-version/cargo-updater.js000064400000000000000000000004761046102023000205050ustar 00000000000000const TOML = require('@iarna/toml') module.exports.readVersion = function (contents) { let data = TOML.parse(contents); return data.package.version; } module.exports.writeVersion = function (contents, version) { let data = TOML.parse(contents); data.package.version = version; return TOML.stringify(data); } maybe-async-0.2.7/.versionrc000064400000000000000000000003301046102023000140510ustar 00000000000000{ "bumpFiles": [ { "filename": "Cargo.toml", "updater": ".standard-version/cargo-updater.js" } ], "packageFiles": [ { "filename": "Cargo.toml", "updater": ".standard-version/cargo-updater.js" } ] } maybe-async-0.2.7/CHANGELOG.md000064400000000000000000000052201046102023000136520ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ### [0.2.7](https://github.com/fMeow/maybe-async-rs/compare/v0.2.6...v0.2.7) (2023-02-01) ### Features * allow `maybe_async` on static ([a08b112](https://github.com/fMeow/maybe-async-rs/commit/a08b11218bab0d1db304a4f68e0230c022632168)) ### Bug Fixes * applying to pub(crate) trait fail ([8cf762f](https://github.com/fMeow/maybe-async-rs/commit/8cf762fdeb1d316716fa01fb2525e5a6f5d25987)) ### [0.2.6](https://github.com/guoli-lyu/maybe-async-rs/compare/v0.2.4...v0.2.6) (2021-05-28) ### Bug Fixes * remove async test if condition not match ([0089daa](https://github.com/guoli-lyu/maybe-async-rs/commit/0089daad6e3419e11d123e8c5c87a1139880027f)) * test is removed when is_sync ([377815a](https://github.com/guoli-lyu/maybe-async-rs/commit/377815a7a81efc4a0332cc2716a7d603b350ff03)) ### [0.2.5](https://github.com/guoli-lyu/maybe-async-rs/compare/v0.2.4...v0.2.5) (2021-05-28) ### Bug Fixes * remove async test if condition not match ([0c49246](https://github.com/guoli-lyu/maybe-async-rs/commit/0c49246a3245773faff482f6b42d66522d2af208)) ### [0.2.4](https://github.com/guoli-lyu/maybe-async-rs/compare/v0.2.3...v0.2.4) (2021-03-28) ### Features * replace generic type of Future with Output ([f296cc0](https://github.com/guoli-lyu/maybe-async-rs/commit/f296cc05c90923ae3a3eeea3c5173d06d642c2ab)) * search trait bound that ends with `Future` ([3508ff2](https://github.com/guoli-lyu/maybe-async-rs/commit/3508ff2987cce61808297aa920c522e0f2012a8a)) ### [0.2.3](https://github.com/guoli-lyu/maybe-async-rs/compare/v0.2.2...v0.2.3) (2021-03-27) ### Bug Fixes * enable full feature gate for syn ([614c085](https://github.com/guoli-lyu/maybe-async-rs/commit/614c085444caf6d0d493422ca20f8ed3b86b7315)) ### [0.2.2](https://github.com/guoli-lyu/maybe-async-rs/compare/v0.2.1...v0.2.2) (2020-10-19) ### Features * avoid extra parenthesis and braces ([8d146f9](https://github.com/guoli-lyu/maybe-async-rs/commit/8d146f9a9234339de1ef6b9f7ffd44421a8d6c68)) * remove parenthesis wrap in await ([bc5f460](https://github.com/guoli-lyu/maybe-async-rs/commit/bc5f46078bfb5ccc1599570303aa72a84cc5e2d7)) * wrap await expr into block instead of paren ([5c4232a](https://github.com/guoli-lyu/maybe-async-rs/commit/5c4232a07035e9c2d4add280cc5b090a7bde471b)) ### [0.2.1](https://github.com/guoli-lyu/maybe-async-rs/compare/v0.2.0...v0.2.1) (2020-10-05) ### Bug Fixes * allow unused_paren when convert to sync ([242ded2](https://github.com/guoli-lyu/maybe-async-rs/commit/242ded2fb9f1cc3c883e0f39a081a555e7a74198)) maybe-async-0.2.7/Cargo.lock0000644000000450220000000000100112300ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", "syn", ] [[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" 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.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" dependencies = [ "async-lock", "autocfg", "concurrent-queue", "futures-lite", "libc", "log", "parking", "polling", "slab", "socket2", "waker-fn", "windows-sys", ] [[package]] name = "async-lock" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" dependencies = [ "event-listener", "futures-lite", ] [[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.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "atomic-waker" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "basic-toml" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e819b667739967cd44d308b8c7b71305d8bb0729ac44a248aa08f33d01950b4" dependencies = [ "serde", ] [[package]] name = "blocking" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" dependencies = [ "async-channel", "async-lock", "async-task", "atomic-waker", "fastrand", "futures-lite", ] [[package]] name = "bumpalo" version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[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.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" 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", ] [[package]] name = "dissimilar" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" [[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.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] [[package]] name = "futures-channel" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-io" version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-lite" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" dependencies = [ "fastrand", "futures-core", "futures-io", "memchr", "parking", "pin-project-lite", "waker-fn", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[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.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] [[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] [[package]] name = "itoa" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" 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.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", "value-bag", ] [[package]] name = "maybe-async" version = "0.2.7" dependencies = [ "async-std", "async-trait", "proc-macro2", "quote", "syn", "tokio", "trybuild", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "num_cpus" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "parking" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[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.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" dependencies = [ "autocfg", "cfg-if", "libc", "log", "wepoll-ffi", "windows-sys", ] [[package]] name = "proc-macro2" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "serde" version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" [[package]] name = "serde_derive" version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "slab" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ "autocfg", ] [[package]] name = "socket2" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", ] [[package]] name = "syn" version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "tokio" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "num_cpus", "pin-project-lite", "tokio-macros", "windows-sys", ] [[package]] name = "tokio-macros" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "trybuild" version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44da5a6f2164c8e14d3bbc0657d69c5966af9f5f6930d4f600b1f5c4a673413" dependencies = [ "basic-toml", "dissimilar", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", ] [[package]] name = "unicode-ident" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "value-bag" version = "1.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" dependencies = [ "ctor", "version_check", ] [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "waker-fn" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "wasm-bindgen" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "wepoll-ffi" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" dependencies = [ "cc", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 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.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" maybe-async-0.2.7/Cargo.toml0000644000000026250000000000100112550ustar # 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 = "maybe-async" version = "0.2.7" authors = ["Guoli Lyu "] description = "A procedure macro to unify SYNC and ASYNC implementation" documentation = "https://docs.rs/maybe-async" readme = "README.md" keywords = [ "maybe", "async", "futures", "macros", "proc_macro", ] license = "MIT" repository = "https://github.com/fMeow/maybe-async-rs" [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "1.0" features = [ "visit-mut", "full", ] [dev-dependencies.async-std] version = "1" features = ["attributes"] [dev-dependencies.async-trait] version = "0.1" [dev-dependencies.tokio] version = "1" features = [ "macros", "rt-multi-thread", ] [dev-dependencies.trybuild] version = "1" features = ["diff"] [features] default = [] is_sync = [] [badges.maintenance] status = "actively-developed" maybe-async-0.2.7/Cargo.toml.orig000064400000000000000000000016231046102023000147330ustar 00000000000000[package] name = "maybe-async" version = "0.2.7" authors = [ "Guoli Lyu " ] edition = "2018" readme = "README.md" license = "MIT" description = "A procedure macro to unify SYNC and ASYNC implementation" repository = "https://github.com/fMeow/maybe-async-rs" documentation = "https://docs.rs/maybe-async" keywords = [ "maybe", "async", "futures", "macros", "proc_macro" ] [dependencies] proc-macro2 = "1.0" quote = "1.0" [dependencies.syn] version = "1.0" features = [ "visit-mut", "full" ] [lib] proc-macro = true [badges.maintenance] status = "actively-developed" [dev-dependencies] async-trait = "0.1" [dev-dependencies.trybuild] version = "1" features = [ "diff" ] [dev-dependencies.async-std] version = "1" features = [ "attributes" ] [dev-dependencies.tokio] version = "1" features = [ "macros", "rt-multi-thread" ] [features] default = [ ] is_sync = [ ] maybe-async-0.2.7/LICENSE000064400000000000000000000020351046102023000130470ustar 00000000000000Copyright (c) 2020 Guoli Lyu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. maybe-async-0.2.7/README.md000064400000000000000000000202101046102023000133140ustar 00000000000000# Maybe-Async Procedure Macro **Why bother writing similar code twice for blocking and async code?** [![Build Status](https://github.com/fMeow/maybe-async-rs/workflows/CI%20%28Linux%29/badge.svg?branch=main)](https://github.com/fMeow/maybe-async-rs/actions) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![Latest Version](https://img.shields.io/crates/v/maybe-async.svg)](https://crates.io/crates/maybe-async) [![maybe-async](https://docs.rs/maybe-async/badge.svg)](https://docs.rs/maybe-async) When implementing both sync and async versions of API in a crate, most API of the two version are almost the same except for some async/await keyword. `maybe-async` help unifying async and sync implementation by **procedural macro**. - Write async code with normal `async`, `await`, and let `maybe_async` handles those `async` and `await` when you need a blocking code. - Switch between sync and async by toggling `is_sync` feature gate in `Cargo.toml`. - use `must_be_async` and `must_be_sync` to keep code in specified version - use `impl_async` and `impl_sync` to only compile code block on specified version - A handy macro to unify unit test code is also provided. These procedural macros can be applied to the following codes: - trait item declaration - trait implmentation - function definition - struct definition **RECOMMENDATION**: Enable **resolver ver2** in your crate, which is introduced in Rust 1.51. If not, two crates in dependency with conflict version (one async and another blocking) can fail complilation. ## Motivation The async/await language feature alters the async world of rust. Comparing with the map/and_then style, now the async code really resembles sync version code. In many crates, the async and sync version of crates shares the same API, but the minor difference that all async code must be awaited prevent the unification of async and sync code. In other words, we are forced to write an async and an sync implementation repectively. ## Macros in Detail `maybe-async` offers 4 set of attribute macros: `maybe_async`, `sync_impl`/`async_impl`, `must_be_sync`/`must_be_async`, and `test`. To use `maybe-async`, we must know which block of codes is only used on blocking implementation, and which on async. These two implementation should share the same function signatures except for async/await keywords, and use `sync_impl` and `async_impl` to mark these implementation. Use `maybe_async` macro on codes that share the same API on both async and blocking code except for async/await keywords. And use feature gate `is_sync` in `Cargo.toml` to toggle between async and blocking code. - `maybe_async` Offers a unified feature gate to provide sync and async conversion on demand by feature gate `is_sync`, with **async first** policy. Want to keep async code? add `maybe_async` in dependencies with default features, which means `maybe_async` is the same as `must_be_async`: ```toml [dependencies] maybe_async = "0.2" ``` Wanna convert async code to sync? Add `maybe_async` to dependencies with an `is_sync` feature gate. In this way, `maybe_async` is the same as `must_be_sync`: ```toml [dependencies] maybe_async = { version = "0.2", features = ["is_sync"] } ``` Not all async traits need futures that are `dyn Future + Send`. To avoid having "Send" and "Sync" bounds placed on the async trait methods, invoke the maybe_async macro as #[maybe_async(?Send)] on both the trait and the impl blocks. - `must_be_async` **Keep async**. Add `async_trait` attribute macro for trait declaration or implementation to bring async fn support in traits. To avoid having "Send" and "Sync" bounds placed on the async trait methods, invoke the maybe_async macro as #[must_be_async(?Send)]. - `must_be_sync` **Convert to sync code**. Convert the async code into sync code by removing all `async move`, `async` and `await` keyword - `sync_impl` An sync implementation should on compile on blocking implementation and must simply disappear when we want async version. Although most of the API are almost the same, there definitely come to a point when the async and sync version should differ greatly. For example, a MongoDB client may use the same API for async and sync verison, but the code to actually send reqeust are quite different. Here, we can use `sync_impl` to mark a synchronous implementation, and a sync implementation shoule disappear when we want async version. - `async_impl` An async implementation should on compile on async implementation and must simply disappear when we want sync version. To avoid having "Send" and "Sync" bounds placed on the async trait methods, invoke the maybe_async macro as #[async_impl(?Send)]. - `test` Handy macro to unify async and sync **unit and e2e test** code. You can specify the condition to compile to sync test code and also the conditions to compile to async test code with given test macro, e.x. `tokio::test`, `async_std::test` and etc. When only sync condition is specified,the test code only compiles when sync condition is met. ```rust #[maybe_async::test( feature="is_sync", async(all(not(feature="is_sync"), feature="async_std"), async_std::test), async(all(not(feature="is_sync"), feature="tokio"), tokio::test) )] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } ``` ## What's Under the Hook `maybe-async` compiles your code in different way with the `is_sync` feature gate. It remove all `await` and `async` keywords in your code under `maybe_async` macro and conditionally compiles codes under `async_impl` and `sync_impl`. Here is an detailed example on what's going on whe the `is_sync` feature gate set or not. ```rust #[maybe_async::maybe_async(?Send)] trait A { async fn async_fn_name() -> Result<(), ()> { Ok(()) } fn sync_fn_name() -> Result<(), ()> { Ok(()) } } struct Foo; #[maybe_async::maybe_async(?Send)] impl A for Foo { async fn async_fn_name() -> Result<(), ()> { Ok(()) } fn sync_fn_name() -> Result<(), ()> { Ok(()) } } #[maybe_async::maybe_async] async fn maybe_async_fn() -> Result<(), ()> { let a = Foo::async_fn_name().await?; let b = Foo::sync_fn_name()?; Ok(()) } ``` When `maybe-async` feature gate `is_sync` is **NOT** set, the generated code is async code: ```rust // Compiled code when `is_sync` is toggled off. #[async_trait::async_trait(?Send)] trait A { async fn maybe_async_fn_name() -> Result<(), ()> { Ok(()) } fn sync_fn_name() -> Result<(), ()> { Ok(()) } } struct Foo; #[async_trait::async_trait(?Send)] impl A for Foo { async fn maybe_async_fn_name() -> Result<(), ()> { Ok(()) } fn sync_fn_name() -> Result<(), ()> { Ok(()) } } async fn maybe_async_fn() -> Result<(), ()> { let a = Foo::maybe_async_fn_name().await?; let b = Foo::sync_fn_name()?; Ok(()) } ``` When `maybe-async` feature gate `is_sync` is set, all async keyword is ignored and yields a sync version code: ```rust // Compiled code when `is_sync` is toggled on. trait A { fn maybe_async_fn_name() -> Result<(), ()> { Ok(()) } fn sync_fn_name() -> Result<(), ()> { Ok(()) } } struct Foo; impl A for Foo { fn maybe_async_fn_name() -> Result<(), ()> { Ok(()) } fn sync_fn_name() -> Result<(), ()> { Ok(()) } } fn maybe_async_fn() -> Result<(), ()> { let a = Foo::maybe_async_fn_name()?; let b = Foo::sync_fn_name()?; Ok(()) } ``` ## Examples ### rust client for services When implementing rust client for any services, like awz3. The higher level API of async and sync version is almost the same, such as creating or deleting a bucket, retrieving an object and etc. The example `service_client` is a proof of concept that `maybe_async` can actually free us from writing almost the same code for sync and async. We can toggle between a sync AWZ3 client and async one by `is_sync` feature gate when we add `maybe-async` to dependency. # License MITmaybe-async-0.2.7/examples/service_client.rs000064400000000000000000000052651046102023000172340ustar 00000000000000#![allow(dead_code, unused_variables)] /// To use `maybe-async`, we must know which block of codes is only used on /// blocking implementation, and which on async. These two implementation should /// share the same API except for async/await keywords, and use `sync_impl` and /// `async_impl` to mark these implementation. type Response = String; type Url = &'static str; type Method = String; /// InnerClient are used to actually send request, /// which differ a lot between sync and async. #[maybe_async::maybe_async] trait InnerClient { async fn request(method: Method, url: Url, data: String) -> Response; #[inline] async fn post(url: Url, data: String) -> Response { Self::request(String::from("post"), url, data).await } #[inline] async fn delete(url: Url, data: String) -> Response { Self::request(String::from("delete"), url, data).await } } /// The higher level API for end user. pub struct ServiceClient; /// Synchronous implementation, only compiles when `is_sync` feature is off. /// Else the compiler will complain that *request is defined multiple times* and /// blabla. #[maybe_async::sync_impl] impl InnerClient for ServiceClient { fn request(method: Method, url: Url, data: String) -> Response { // your implementation for sync, like use // `reqwest::blocking` to send request String::from("pretend we have a response") } } /// Asynchronous implementation, only compiles when `is_sync` feature is off. #[maybe_async::async_impl] impl InnerClient for ServiceClient { async fn request(method: Method, url: Url, data: String) -> Response { // your implementation for async, like use `reqwest::client` // or `async_std` to send request String::from("pretend we have a response") } } /// Code of upstream API are almost the same for sync and async, /// except for async/await keyword. impl ServiceClient { #[maybe_async::maybe_async] async fn create_bucket(name: String) -> Response { Self::post("http://correct_url4create", String::from("my_bucket")).await // When `is_sync` is toggle on, this block will compiles to: // Self::post("http://correct_url4create", String::from("my_bucket")) } #[maybe_async::maybe_async] async fn delete_bucket(name: String) -> Response { Self::delete("http://correct_url4delete", String::from("my_bucket")).await } // and another thousands of functions that interact with service side } #[maybe_async::sync_impl] fn main() { let _ = ServiceClient::create_bucket("bucket".to_owned()); } #[maybe_async::async_impl] #[tokio::main] async fn main() { let _ = ServiceClient::create_bucket("bucket".to_owned()).await; } maybe-async-0.2.7/src/lib.rs000064400000000000000000000505351046102023000137550ustar 00000000000000//! //! # Maybe-Async Procedure Macro //! //! **Why bother writing similar code twice for blocking and async code?** //! //! [![Build Status](https://github.com/fMeow/maybe-async-rs/workflows/CI%20%28Linux%29/badge.svg?branch=main)](https://github.com/fMeow/maybe-async-rs/actions) //! [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) //! [![Latest Version](https://img.shields.io/crates/v/maybe-async.svg)](https://crates.io/crates/maybe-async) //! [![maybe-async](https://docs.rs/maybe-async/badge.svg)](https://docs.rs/maybe-async) //! //! When implementing both sync and async versions of API in a crate, most API //! of the two version are almost the same except for some async/await keyword. //! //! `maybe-async` help unifying async and sync implementation by **procedural //! macro**. //! - Write async code with normal `async`, `await`, and let `maybe_async` //! handles //! those `async` and `await` when you need a blocking code. //! - Switch between sync and async by toggling `is_sync` feature gate in //! `Cargo.toml`. //! - use `must_be_async` and `must_be_sync` to keep code in specified version //! - use `impl_async` and `impl_sync` to only compile code block on specified //! version //! - A handy macro to unify unit test code is also provided. //! //! These procedural macros can be applied to the following codes: //! - trait item declaration //! - trait implmentation //! - function definition //! - struct definition //! //! **RECOMMENDATION**: Enable **resolver ver2** in your crate, which is //! introduced in Rust 1.51. If not, two crates in dependency with conflict //! version (one async and another blocking) can fail complilation. //! //! //! ## Motivation //! //! The async/await language feature alters the async world of rust. //! Comparing with the map/and_then style, now the async code really resembles //! sync version code. //! //! In many crates, the async and sync version of crates shares the same API, //! but the minor difference that all async code must be awaited prevent the //! unification of async and sync code. In other words, we are forced to write //! an async and an sync implementation repectively. //! //! ## Macros in Detail //! //! `maybe-async` offers 4 set of attribute macros: `maybe_async`, //! `sync_impl`/`async_impl`, `must_be_sync`/`must_be_async`, and `test`. //! //! To use `maybe-async`, we must know which block of codes is only used on //! blocking implementation, and which on async. These two implementation should //! share the same function signatures except for async/await keywords, and use //! `sync_impl` and `async_impl` to mark these implementation. //! //! Use `maybe_async` macro on codes that share the same API on both async and //! blocking code except for async/await keywords. And use feature gate //! `is_sync` in `Cargo.toml` to toggle between async and blocking code. //! //! - `maybe_async` //! //! Offers a unified feature gate to provide sync and async conversion on //! demand by feature gate `is_sync`, with **async first** policy. //! //! Want to keep async code? add `maybe_async` in dependencies with default //! features, which means `maybe_async` is the same as `must_be_async`: //! //! ```toml //! [dependencies] //! maybe_async = "0.2" //! ``` //! //! Wanna convert async code to sync? Add `maybe_async` to dependencies with //! an `is_sync` feature gate. In this way, `maybe_async` is the same as //! `must_be_sync`: //! //! ```toml //! [dependencies] //! maybe_async = { version = "0.2", features = ["is_sync"] } //! ``` //! //! Not all async traits need futures that are `dyn Future + Send`. //! To avoid having "Send" and "Sync" bounds placed on the async trait //! methods, invoke the maybe_async macro as #[maybe_async(?Send)] on both //! the trait and the impl blocks. //! //! //! - `must_be_async` //! //! **Keep async**. Add `async_trait` attribute macro for trait declaration //! or implementation to bring async fn support in traits. //! //! To avoid having "Send" and "Sync" bounds placed on the async trait //! methods, invoke the maybe_async macro as #[must_be_async(?Send)]. //! //! - `must_be_sync` //! //! **Convert to sync code**. Convert the async code into sync code by //! removing all `async move`, `async` and `await` keyword //! //! //! - `sync_impl` //! //! An sync implementation should on compile on blocking implementation and //! must simply disappear when we want async version. //! //! Although most of the API are almost the same, there definitely come to a //! point when the async and sync version should differ greatly. For //! example, a MongoDB client may use the same API for async and sync //! verison, but the code to actually send reqeust are quite different. //! //! Here, we can use `sync_impl` to mark a synchronous implementation, and a //! sync implementation shoule disappear when we want async version. //! //! - `async_impl` //! //! An async implementation should on compile on async implementation and //! must simply disappear when we want sync version. //! //! To avoid having "Send" and "Sync" bounds placed on the async trait //! methods, invoke the maybe_async macro as #[async_impl(?Send)]. //! //! //! - `test` //! //! Handy macro to unify async and sync **unit and e2e test** code. //! //! You can specify the condition to compile to sync test code //! and also the conditions to compile to async test code with given test //! macro, e.x. `tokio::test`, `async_std::test` and etc. When only sync //! condition is specified,the test code only compiles when sync condition //! is met. //! //! ```rust //! # #[maybe_async::maybe_async] //! # async fn async_fn() -> bool { //! # true //! # } //! //! ##[maybe_async::test( //! feature="is_sync", //! async( //! all(not(feature="is_sync"), feature="async_std"), //! async_std::test //! ), //! async( //! all(not(feature="is_sync"), feature="tokio"), //! tokio::test //! ) //! )] //! async fn test_async_fn() { //! let res = async_fn().await; //! assert_eq!(res, true); //! } //! ``` //! //! ## What's Under the Hook //! //! `maybe-async` compiles your code in different way with the `is_sync` feature //! gate. It remove all `await` and `async` keywords in your code under //! `maybe_async` macro and conditionally compiles codes under `async_impl` and //! `sync_impl`. //! //! Here is an detailed example on what's going on whe the `is_sync` feature //! gate set or not. //! //! ```rust //! #[maybe_async::maybe_async(?Send)] //! trait A { //! async fn async_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! fn sync_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! } //! //! struct Foo; //! //! #[maybe_async::maybe_async(?Send)] //! impl A for Foo { //! async fn async_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! fn sync_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! } //! //! #[maybe_async::maybe_async] //! async fn maybe_async_fn() -> Result<(), ()> { //! let a = Foo::async_fn_name().await?; //! //! let b = Foo::sync_fn_name()?; //! Ok(()) //! } //! ``` //! //! When `maybe-async` feature gate `is_sync` is **NOT** set, the generated code //! is async code: //! //! ```rust //! // Compiled code when `is_sync` is toggled off. //! #[async_trait::async_trait(?Send)] //! trait A { //! async fn maybe_async_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! fn sync_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! } //! //! struct Foo; //! //! #[async_trait::async_trait(?Send)] //! impl A for Foo { //! async fn maybe_async_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! fn sync_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! } //! //! async fn maybe_async_fn() -> Result<(), ()> { //! let a = Foo::maybe_async_fn_name().await?; //! let b = Foo::sync_fn_name()?; //! Ok(()) //! } //! ``` //! //! When `maybe-async` feature gate `is_sync` is set, all async keyword is //! ignored and yields a sync version code: //! //! ```rust //! // Compiled code when `is_sync` is toggled on. //! trait A { //! fn maybe_async_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! fn sync_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! } //! //! struct Foo; //! //! impl A for Foo { //! fn maybe_async_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! fn sync_fn_name() -> Result<(), ()> { //! Ok(()) //! } //! } //! //! fn maybe_async_fn() -> Result<(), ()> { //! let a = Foo::maybe_async_fn_name()?; //! let b = Foo::sync_fn_name()?; //! Ok(()) //! } //! ``` //! //! ## Examples //! //! ### rust client for services //! //! When implementing rust client for any services, like awz3. The higher level //! API of async and sync version is almost the same, such as creating or //! deleting a bucket, retrieving an object and etc. //! //! The example `service_client` is a proof of concept that `maybe_async` can //! actually free us from writing almost the same code for sync and async. We //! can toggle between a sync AWZ3 client and async one by `is_sync` feature //! gate when we add `maybe-async` to dependency. //! //! //! # License //! MIT extern crate proc_macro; use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use syn::{ parse_macro_input, spanned::Spanned, AttributeArgs, ImplItem, Lit, Meta, NestedMeta, TraitItem, }; use quote::quote; use crate::{parse::Item, visit::AsyncAwaitRemoval}; mod parse; mod visit; fn convert_async(input: &mut Item, send: bool) -> TokenStream2 { if send { match input { Item::Impl(item) => quote!(#[async_trait::async_trait]#item), Item::Trait(item) => quote!(#[async_trait::async_trait]#item), Item::Fn(item) => quote!(#item), Item::Static(item) => quote!(#item), } } else { match input { Item::Impl(item) => quote!(#[async_trait::async_trait(?Send)]#item), Item::Trait(item) => quote!(#[async_trait::async_trait(?Send)]#item), Item::Fn(item) => quote!(#item), Item::Static(item) => quote!(#item), } } .into() } fn convert_sync(input: &mut Item) -> TokenStream2 { match input { Item::Impl(item) => { for inner in &mut item.items { if let ImplItem::Method(ref mut method) = inner { if method.sig.asyncness.is_some() { method.sig.asyncness = None; } } } AsyncAwaitRemoval.remove_async_await(quote!(#item)) } Item::Trait(item) => { for inner in &mut item.items { if let TraitItem::Method(ref mut method) = inner { if method.sig.asyncness.is_some() { method.sig.asyncness = None; } } } AsyncAwaitRemoval.remove_async_await(quote!(#item)) } Item::Fn(item) => { if item.sig.asyncness.is_some() { item.sig.asyncness = None; } AsyncAwaitRemoval.remove_async_await(quote!(#item)) } Item::Static(item) => AsyncAwaitRemoval.remove_async_await(quote!(#item)), } .into() } /// maybe_async attribute macro /// /// Can be applied to trait item, trait impl, functions and struct impls. #[proc_macro_attribute] pub fn maybe_async(args: TokenStream, input: TokenStream) -> TokenStream { let send = match args.to_string().replace(" ", "").as_str() { "" | "Send" => true, "?Send" => false, _ => { return syn::Error::new(Span::call_site(), "Only accepts `Send` or `?Send`") .to_compile_error() .into(); } }; let mut item = parse_macro_input!(input as Item); let token = if cfg!(feature = "is_sync") { convert_sync(&mut item) } else { convert_async(&mut item, send) }; token.into() } /// convert marked async code to async code with `async-trait` #[proc_macro_attribute] pub fn must_be_async(args: TokenStream, input: TokenStream) -> TokenStream { let send = match args.to_string().replace(" ", "").as_str() { "" | "Send" => true, "?Send" => false, _ => { return syn::Error::new(Span::call_site(), "Only accepts `Send` or `?Send`") .to_compile_error() .into(); } }; let mut item = parse_macro_input!(input as Item); convert_async(&mut item, send).into() } /// convert marked async code to sync code #[proc_macro_attribute] pub fn must_be_sync(_args: TokenStream, input: TokenStream) -> TokenStream { let mut item = parse_macro_input!(input as Item); convert_sync(&mut item).into() } /// mark sync implementation /// /// only compiled when `is_sync` feature gate is set. /// When `is_sync` is not set, marked code is removed. #[proc_macro_attribute] pub fn sync_impl(_args: TokenStream, input: TokenStream) -> TokenStream { let input = TokenStream2::from(input); let token = if cfg!(feature = "is_sync") { quote!(#input) } else { quote!() }; token.into() } /// mark async implementation /// /// only compiled when `is_sync` feature gate is not set. /// When `is_sync` is set, marked code is removed. #[proc_macro_attribute] pub fn async_impl(args: TokenStream, _input: TokenStream) -> TokenStream { let send = match args.to_string().replace(" ", "").as_str() { "" | "Send" => true, "?Send" => false, _ => { return syn::Error::new(Span::call_site(), "Only accepts `Send` or `?Send`") .to_compile_error() .into(); } }; let token = if cfg!(feature = "is_sync") { quote!() } else { let mut item = parse_macro_input!(_input as Item); convert_async(&mut item, send) }; token.into() } macro_rules! match_nested_meta_to_str_lit { ($t:expr) => { match $t { NestedMeta::Lit(lit) => { match lit { Lit::Str(s) => { s.value().parse::().unwrap() } _ => { return syn::Error::new(lit.span(), "expected meta or string literal").to_compile_error().into(); } } } NestedMeta::Meta(meta) => quote!(#meta) } }; } /// Handy macro to unify test code of sync and async code /// /// Since the API of both sync and async code are the same, /// with only difference that async functions must be awaited. /// So it's tedious to write unit sync and async respectively. /// /// This macro helps unify the sync and async unit test code. /// Pass the condition to treat test code as sync as the first /// argument. And specify the condition when to treat test code /// as async and the lib to run async test, e.x. `async-std::test`, /// `tokio::test`, or any valid attribute macro. /// /// **ATTENTION**: do not write await inside a assert macro /// /// - Examples /// /// ```rust /// #[maybe_async::maybe_async] /// async fn async_fn() -> bool { /// true /// } /// /// #[maybe_async::test( /// // when to treat the test code as sync version /// feature="is_sync", /// // when to run async test /// async(all(not(feature="is_sync"), feature="async_std"), async_std::test), /// // you can specify multiple conditions for different async runtime /// async(all(not(feature="is_sync"), feature="tokio"), tokio::test) /// )] /// async fn test_async_fn() { /// let res = async_fn().await; /// assert_eq!(res, true); /// } /// /// // Only run test in sync version /// #[maybe_async::test(feature = "is_sync")] /// async fn test_sync_fn() { /// let res = async_fn().await; /// assert_eq!(res, true); /// } /// ``` /// /// The above code is transcripted to the following code: /// /// ```rust /// # use maybe_async::{must_be_async, must_be_sync, sync_impl}; /// # #[maybe_async::maybe_async] /// # async fn async_fn() -> bool { true } /// /// // convert to sync version when sync condition is met, keep in async version when corresponding /// // condition is met /// #[cfg_attr(feature = "is_sync", must_be_sync, test)] /// #[cfg_attr( /// all(not(feature = "is_sync"), feature = "async_std"), /// must_be_async, /// async_std::test /// )] /// #[cfg_attr( /// all(not(feature = "is_sync"), feature = "tokio"), /// must_be_async, /// tokio::test /// )] /// async fn test_async_fn() { /// let res = async_fn().await; /// assert_eq!(res, true); /// } /// /// // force converted to sync function, and only compile on sync condition /// #[cfg(feature = "is_sync")] /// #[test] /// fn test_sync_fn() { /// let res = async_fn(); /// assert_eq!(res, true); /// } /// ``` #[proc_macro_attribute] pub fn test(args: TokenStream, input: TokenStream) -> TokenStream { let attr_args = parse_macro_input!(args as AttributeArgs); let input = TokenStream2::from(input); if attr_args.len() < 1 { return syn::Error::new( Span::call_site(), "Arguments cannot be empty, at least specify the condition for sync code", ) .to_compile_error() .into(); } // The first attributes indicates sync condition let sync_cond = match_nested_meta_to_str_lit!(attr_args.first().unwrap()); let mut ts = quote!(#[cfg_attr(#sync_cond, maybe_async::must_be_sync, test)]); // The rest attributes indicates async condition and async test macro // only accepts in the forms of `async(cond, test_macro)`, but `cond` and // `test_macro` can be either meta attributes or string literal let mut async_token = Vec::new(); let mut async_conditions = Vec::new(); for async_meta in attr_args.into_iter().skip(1) { match async_meta { NestedMeta::Meta(meta) => match meta { Meta::List(list) => { let name = list.path.segments[0].ident.to_string(); if name.ne("async") { return syn::Error::new( list.path.span(), format!("Unknown path: `{}`, must be `async`", name), ) .to_compile_error() .into(); } if list.nested.len() == 2 { let async_cond = match_nested_meta_to_str_lit!(list.nested.first().unwrap()); let async_test = match_nested_meta_to_str_lit!(list.nested.last().unwrap()); let attr = quote!( #[cfg_attr(#async_cond, maybe_async::must_be_async, #async_test)] ); async_conditions.push(async_cond); async_token.push(attr); } else { let msg = format!( "Must pass two metas or string literals like `async(condition, \ async_test_macro)`, you passed {} metas.", list.nested.len() ); return syn::Error::new(list.span(), msg).to_compile_error().into(); } } _ => { return syn::Error::new( meta.span(), "Must be list of metas like: `async(condition, async_test_macro)`", ) .to_compile_error() .into(); } }, NestedMeta::Lit(lit) => { return syn::Error::new( lit.span(), "Must be list of metas like: `async(condition, async_test_macro)`", ) .to_compile_error() .into(); } }; } async_token.into_iter().for_each(|t| ts.extend(t)); ts.extend(quote!( #input )); if !async_conditions.is_empty() { quote! { #[cfg(any(#sync_cond, #(#async_conditions),*))] #ts } } else { quote! { #[cfg(#sync_cond)] #ts } } .into() } maybe-async-0.2.7/src/parse.rs000064400000000000000000000027241046102023000143160ustar 00000000000000use proc_macro2::Span; use syn::{ parse::{discouraged::Speculative, Parse, ParseStream, Result}, Attribute, Error, ItemFn, ItemImpl, ItemStatic, ItemTrait, }; pub enum Item { Trait(ItemTrait), Impl(ItemImpl), Fn(ItemFn), Static(ItemStatic), } macro_rules! fork { ($fork:ident = $input:ident) => {{ $fork = $input.fork(); &$fork }}; } impl Parse for Item { fn parse(input: ParseStream) -> Result { let attrs = input.call(Attribute::parse_outer)?; let mut fork; let item = if let Some(mut item) = fork!(fork = input).parse::().ok() { if item.trait_.is_none() { return Err(Error::new(Span::call_site(), "expected a trait impl")); } item.attrs = attrs; Item::Impl(item) } else if let Some(mut item) = fork!(fork = input).parse::().ok() { item.attrs = attrs; Item::Trait(item) } else if let Some(mut item) = fork!(fork = input).parse::().ok() { item.attrs = attrs; Item::Fn(item) } else if let Some(mut item) = fork!(fork = input).parse::().ok() { item.attrs = attrs; Item::Static(item) } else { return Err(Error::new( Span::call_site(), "expected trait impl, trait or fn", )); }; input.advance_to(&fork); Ok(item) } } maybe-async-0.2.7/src/visit.rs000064400000000000000000000160041046102023000143360ustar 00000000000000use std::iter::FromIterator; use proc_macro2::TokenStream; use quote::quote; use syn::{ parse_quote, punctuated::Punctuated, visit_mut::{self, visit_item_mut, visit_path_segment_mut, VisitMut}, Expr, ExprBlock, File, GenericArgument, GenericParam, Item, PathArguments, PathSegment, Type, TypeParamBound, WherePredicate, }; pub struct ReplaceGenericType<'a> { generic_type: &'a str, arg_type: &'a PathSegment, } impl<'a> ReplaceGenericType<'a> { pub fn new(generic_type: &'a str, arg_type: &'a PathSegment) -> Self { Self { generic_type, arg_type, } } pub fn replace_generic_type(item: &mut Item, generic_type: &'a str, arg_type: &'a PathSegment) { let mut s = Self::new(generic_type, arg_type); s.visit_item_mut(item); } } impl<'a> VisitMut for ReplaceGenericType<'a> { fn visit_item_mut(&mut self, i: &mut Item) { if let Item::Fn(item_fn) = i { // remove generic type from generics let args = item_fn .sig .generics .params .iter() .filter_map(|param| { if let GenericParam::Type(type_param) = ¶m { if type_param.ident.to_string().eq(self.generic_type) { None } else { Some(param) } } else { Some(param) } }) .collect::>(); item_fn.sig.generics.params = Punctuated::from_iter(args.into_iter().map(|p| p.clone()).collect::>()); // remove generic type from where clause if let Some(where_clause) = &mut item_fn.sig.generics.where_clause { let new_where_clause = where_clause .predicates .iter() .filter_map(|predicate| { if let WherePredicate::Type(predicate_type) = predicate { if let Type::Path(p) = &predicate_type.bounded_ty { if p.path.segments[0].ident.to_string().eq(self.generic_type) { None } else { Some(predicate) } } else { Some(predicate) } } else { Some(predicate) } }) .collect::>(); where_clause.predicates = Punctuated::from_iter( new_where_clause .into_iter() .map(|c| c.clone()) .collect::>(), ); }; } visit_item_mut(self, i) } fn visit_path_segment_mut(&mut self, i: &mut PathSegment) { // replace generic type with target type if i.ident.to_string().eq(&self.generic_type) { *i = self.arg_type.clone(); } visit_path_segment_mut(self, i); } } pub struct AsyncAwaitRemoval; impl AsyncAwaitRemoval { pub fn remove_async_await(&mut self, item: TokenStream) -> TokenStream { let mut syntax_tree: File = syn::parse(item.into()).unwrap(); self.visit_file_mut(&mut syntax_tree); quote!(#syntax_tree) } } impl VisitMut for AsyncAwaitRemoval { fn visit_expr_mut(&mut self, node: &mut Expr) { // Delegate to the default impl to visit nested expressions. visit_mut::visit_expr_mut(self, node); match node { Expr::Await(expr) => *node = (*expr.base).clone(), Expr::Async(expr) => { let inner = &expr.block; let sync_expr = if inner.stmts.len() == 1 { // remove useless braces when there is only one statement let stmt = &inner.stmts.get(0).unwrap(); // convert statement to Expr parse_quote!(#stmt) } else { Expr::Block(ExprBlock { attrs: expr.attrs.clone(), block: inner.clone(), label: None, }) }; *node = sync_expr; } _ => {} } } fn visit_item_mut(&mut self, i: &mut Item) { // find generic parameter of Future and replace it with its Output type if let Item::Fn(item_fn) = i { let mut inputs: Vec<(String, PathSegment)> = vec![]; // generic params: , F> for param in &item_fn.sig.generics.params { // generic param: T:Future if let GenericParam::Type(type_param) = param { let generic_type_name = type_param.ident.to_string(); // bound: Future for bound in &type_param.bounds { inputs.extend(search_trait_bound(&generic_type_name, bound)); } } } if let Some(where_clause) = &item_fn.sig.generics.where_clause { for predicate in &where_clause.predicates { if let WherePredicate::Type(predicate_type) = predicate { let generic_type_name = if let Type::Path(p) = &predicate_type.bounded_ty { p.path.segments[0].ident.to_string() } else { panic!("Please submit an issue"); }; for bound in &predicate_type.bounds { inputs.extend(search_trait_bound(&generic_type_name, bound)); } } } } for (generic_type_name, path_seg) in &inputs { ReplaceGenericType::replace_generic_type(i, generic_type_name, path_seg); } } visit_item_mut(self, i); } } fn search_trait_bound( generic_type_name: &str, bound: &TypeParamBound, ) -> Vec<(String, PathSegment)> { let mut inputs = vec![]; if let TypeParamBound::Trait(trait_bound) = bound { let segment = &trait_bound.path.segments[trait_bound.path.segments.len() - 1]; let name = segment.ident.to_string(); if name.eq("Future") { // match Future if let PathArguments::AngleBracketed(args) = &segment.arguments { // binding: Output=Type if let GenericArgument::Binding(binding) = &args.args[0] { if let Type::Path(p) = &binding.ty { inputs.push((generic_type_name.to_owned(), p.path.segments[0].clone())); } } } } } inputs } maybe-async-0.2.7/tests/test.rs000064400000000000000000000011241046102023000145270ustar 00000000000000#[test] fn ui() { let t = trybuild::TestCases::new(); t.pass("tests/ui/01-maybe-async.rs"); t.pass("tests/ui/02-must-be-async.rs"); t.pass("tests/ui/03-must-be-sync.rs"); t.pass("tests/ui/04-unit-test-util.rs"); t.pass("tests/ui/05-replace-future-generic-type-with-output.rs"); t.pass("tests/ui/06-sync_impl_async_impl.rs"); t.compile_fail("tests/ui/test_fail/01-empty-test.rs"); t.compile_fail("tests/ui/test_fail/02-unknown-path.rs"); t.compile_fail("tests/ui/test_fail/03-async-gt2.rs"); t.compile_fail("tests/ui/test_fail/04-bad-sync-cond.rs"); } maybe-async-0.2.7/tests/ui/01-maybe-async.rs000064400000000000000000000024761046102023000166260ustar 00000000000000#![allow(dead_code)] use maybe_async::maybe_async; #[maybe_async(Send)] trait Trait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async(?Send)] pub trait PubTrait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async] pub(crate) trait PubCrateTrait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async] async fn async_fn() {} #[maybe_async] pub async fn pub_async_fn() {} #[maybe_async] pub(crate) async fn pub_crate_async_fn() {} #[maybe_async] unsafe fn unsafe_fn() {} struct Struct; #[maybe_async] impl Trait for Struct { fn sync_fn() {} async fn declare_async(&self) {} async fn async_fn(&self) { async { self.declare_async().await }.await } } #[cfg(feature = "is_sync")] fn main() -> std::result::Result<(), ()> { let s = Struct; s.declare_async(); s.async_fn(); async_fn(); pub_async_fn(); Ok(()) } #[cfg(not(feature = "is_sync"))] #[async_std::main] async fn main() { let s = Struct; s.declare_async().await; s.async_fn().await; async_fn().await; pub_async_fn().await; } maybe-async-0.2.7/tests/ui/02-must-be-async.rs000064400000000000000000000035341046102023000171020ustar 00000000000000#![allow(dead_code)] #[maybe_async::maybe_async] trait Trait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async::maybe_async(?Send)] trait NotSendTrait { async fn declare_async_not_send(&self); async fn async_fn_not_send(&self) { self.declare_async_not_send().await } } #[maybe_async::maybe_async] pub trait PubTrait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async::maybe_async] pub(crate) trait PubCrateTrait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[cfg(not(feature = "is_sync"))] #[maybe_async::must_be_async] async fn async_fn() {} #[cfg(not(feature = "is_sync"))] #[maybe_async::must_be_async] pub async fn pub_async_fn() {} #[cfg(not(feature = "is_sync"))] #[maybe_async::maybe_async] pub(crate) async fn pub_crate_async_fn() {} #[cfg(not(feature = "is_sync"))] #[maybe_async::maybe_async] unsafe fn unsafe_fn() {} struct Struct; #[cfg(not(feature = "is_sync"))] #[maybe_async::must_be_async] impl Trait for Struct { fn sync_fn() {} async fn declare_async(&self) {} async fn async_fn(&self) { async { self.declare_async().await }.await } } #[cfg(not(feature = "is_sync"))] #[maybe_async::must_be_async(?Send)] impl NotSendTrait for Struct { async fn declare_async_not_send(&self) {} async fn async_fn_not_send(&self) { async { self.declare_async_not_send().await }.await } } #[cfg(feature = "is_sync")] fn main() {} #[cfg(not(feature = "is_sync"))] #[async_std::main] async fn main() { let s = Struct; s.declare_async().await; s.async_fn().await; async_fn().await; pub_async_fn().await; } maybe-async-0.2.7/tests/ui/03-must-be-sync.rs000064400000000000000000000024351046102023000167410ustar 00000000000000#![allow(dead_code)] #[maybe_async::maybe_async] trait Trait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async::maybe_async] pub trait PubTrait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async::maybe_async] pub(crate) trait PubCrateTrait { fn sync_fn() {} async fn declare_async(&self); async fn async_fn(&self) { self.declare_async().await } } #[maybe_async::maybe_async] async fn async_fn() {} #[maybe_async::maybe_async] pub async fn pub_async_fn() {} #[maybe_async::maybe_async] pub(crate) async fn pub_crate_async_fn() {} #[maybe_async::maybe_async] unsafe fn unsafe_fn() {} struct Struct; #[cfg(feature = "is_sync")] #[maybe_async::must_be_sync] impl Trait for Struct { fn sync_fn() {} async fn declare_async(&self) {} async fn async_fn(&self) { async { self.declare_async().await }.await } } #[cfg(feature = "is_sync")] fn main() -> std::result::Result<(), ()> { let s = Struct; s.declare_async(); s.async_fn(); async_fn(); pub_async_fn(); Ok(()) } #[cfg(not(feature = "is_sync"))] #[async_std::main] async fn main() {} maybe-async-0.2.7/tests/ui/04-unit-test-util.rs000064400000000000000000000016461046102023000173260ustar 00000000000000use maybe_async::maybe_async; #[maybe_async] async fn async_fn() -> bool { true } #[maybe_async::test( feature = "is_sync", async(all(not(feature="is_sync"), feature = "async_std"), async_std::test), async(all(not(feature="is_sync"), feature = "tokio"), tokio::test) )] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } #[maybe_async::test(feature = "is_sync", async(not(feature = "is_sync"), async_std::test))] async fn test_async_fn2() { let res = async_fn().await; assert_eq!(res, true); } #[maybe_async::test("feature=\"is_sync\"", async(not(feature = "is_sync"), async_std::test))] async fn test_async_fn3() { let res = async_fn().await; assert_eq!(res, true); } #[maybe_async::test(feature = "is_sync", async("not(feature = \"is_sync\")", "async_std::test"))] async fn test_async_fn4() { let res = async_fn().await; assert_eq!(res, true); } fn main() { } maybe-async-0.2.7/tests/ui/05-replace-future-generic-type-with-output.rs000064400000000000000000000013301046102023000242310ustar 00000000000000#![allow(unused_imports)] use std::future::Future; #[maybe_async::maybe_async] pub async fn with_fn>>( test: T, ) -> Result<(), ()> where T: FnOnce() -> F, { test().await } #[maybe_async::maybe_async] pub async fn with_fn_where(test: T) -> Result<(), ()> where T: FnOnce() -> F, F: Sync + Future>, { test().await } #[maybe_async::sync_impl] fn main() { with_fn(|| Ok(())).unwrap(); with_fn_where(|| Ok(())).unwrap(); } #[maybe_async::async_impl] #[tokio::main] async fn main() { with_fn(|| async { Ok(()) }).await.unwrap(); with_fn_where(|| async { Ok(()) }).await.unwrap(); } maybe-async-0.2.7/tests/ui/06-sync_impl_async_impl.rs000064400000000000000000000020731046102023000206270ustar 00000000000000#![allow(dead_code, unused_variables)] /// InnerClient differ a lot between sync and async. #[maybe_async::maybe_async] trait Trait { async fn maybe_async_fn(); } /// The higher level API for end user. pub struct Struct; /// Synchronous implementation, only compiles when `is_sync` feature is off. /// Else the compiler will complain that *request is defined multiple times* and /// blabla. #[maybe_async::sync_impl] impl Trait for Struct { fn maybe_async_fn() { } } /// Asynchronous implementation, only compiles when `is_sync` feature is off. #[maybe_async::async_impl] impl Trait for Struct { async fn maybe_async_fn() { } } impl Struct { #[maybe_async::maybe_async] async fn another_maybe_async_fn() { Self::maybe_async_fn().await // When `is_sync` is toggle on, this block will compiles to: // Self::maybe_async_fn() } } #[maybe_async::sync_impl] fn main() { let _ = Struct::another_maybe_async_fn(); } #[maybe_async::async_impl] #[tokio::main] async fn main() { let _ = Struct::another_maybe_async_fn().await; } maybe-async-0.2.7/tests/ui/test_fail/01-empty-test.rs000064400000000000000000000004121046102023000204670ustar 00000000000000use maybe_async::maybe_async; #[maybe_async] async fn async_fn() -> bool { true } // at least one sync condition should be specified #[maybe_async::test()] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } fn main() { } maybe-async-0.2.7/tests/ui/test_fail/01-empty-test.stderr000064400000000000000000000005041046102023000213500ustar 00000000000000error: Arguments cannot be empty, at least specify the condition for sync code --> tests/ui/test_fail/01-empty-test.rs:9:1 | 9 | #[maybe_async::test()] | ^^^^^^^^^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `maybe_async::test` (in Nightly builds, run with -Z macro-backtrace for more info) maybe-async-0.2.7/tests/ui/test_fail/02-unknown-path.rs000064400000000000000000000004701046102023000210120ustar 00000000000000use maybe_async::maybe_async; #[maybe_async] async fn async_fn() -> bool { true } // should only accept `async` #[maybe_async::test(feature="is_sync", unknown(not(feature="is_sync"), async_std::test))] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } fn main() { } maybe-async-0.2.7/tests/ui/test_fail/02-unknown-path.stderr000064400000000000000000000003651046102023000216740ustar 00000000000000error: Unknown path: `unknown`, must be `async` --> tests/ui/test_fail/02-unknown-path.rs:9:40 | 9 | #[maybe_async::test(feature="is_sync", unknown(not(feature="is_sync"), async_std::test))] | ^^^^^^^ maybe-async-0.2.7/tests/ui/test_fail/03-async-gt2.rs000064400000000000000000000004301046102023000201650ustar 00000000000000use maybe_async::maybe_async; #[maybe_async] async fn async_fn() -> bool { true } #[maybe_async::test(feature="is_sync", async(feature="async", async_std::test, added))] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } fn main() { } maybe-async-0.2.7/tests/ui/test_fail/03-async-gt2.stderr000064400000000000000000000004531046102023000210510ustar 00000000000000error: Must pass two metas or string literals like `async(condition, async_test_macro)`, you passed 3 metas. --> tests/ui/test_fail/03-async-gt2.rs:8:40 | 8 | #[maybe_async::test(feature="is_sync", async(feature="async", async_std::test, added))] | ^^^^^ maybe-async-0.2.7/tests/ui/test_fail/04-bad-sync-cond.rs000064400000000000000000000004251046102023000210040ustar 00000000000000use maybe_async::maybe_async; #[maybe_async] async fn async_fn() -> bool { true } // bad sync condition #[maybe_async::test(unknown(feature="async", async_std::test))] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } fn main() { }maybe-async-0.2.7/tests/ui/test_fail/04-bad-sync-cond.stderr000064400000000000000000000003451046102023000216640ustar 00000000000000error[E0537]: invalid predicate `unknown` --> tests/ui/test_fail/04-bad-sync-cond.rs:9:21 | 9 | #[maybe_async::test(unknown(feature="async", async_std::test))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ maybe-async-0.2.7/tests/unit-test-util.rs000064400000000000000000000012761046102023000164670ustar 00000000000000use maybe_async::maybe_async; #[maybe_async] async fn async_fn() -> bool { true } #[maybe_async::test(feature = "is_sync", async(not(feature = "is_sync"), async_std::test))] async fn test_async_fn() { let res = async_fn().await; assert_eq!(res, true); } #[maybe_async::test(feature = "is_sync", async(not(feature = "is_sync"), tokio::test))] async fn test_async_fn2() { let res = async_fn().await; assert_eq!(res, true); } #[maybe_async::test(feature = "is_sync")] async fn test_async_fn3() { let res = async_fn().await; assert_eq!(res, true); } #[maybe_async::test(feature = "is_sync")] async fn test_sync_fn() { let res = async_fn(); assert_eq!(res, true); }