aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2021-02-18 12:05:23 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-02-18 12:05:23 +0000
commit933a786e24ae9749ce6d73dd8c882ce420a6c8db (patch)
tree3bc261bbf5db0e4e8e5c3e3f55140fd6a182a560
parenta0b20b1c027183c3ccefef42435b43ba2b62b15e (diff)
parent1c2147001356d4be84e73b929489036c89882290 (diff)
downloadasync-stream-933a786e24ae9749ce6d73dd8c882ce420a6c8db.tar.gz
Import async-stream v0.3.0 am: 647493e10d am: d822959c82 am: 1c21470013
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/async-stream/+/1592880 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Ibd2de8d95e52d8f876e7c60f012ac14886aaaef1
-rw-r--r--.cargo_vcs_info.json5
-rw-r--r--Android.bp21
-rw-r--r--Cargo.lock552
-rw-r--r--Cargo.toml40
-rw-r--r--Cargo.toml.orig30
-rw-r--r--LICENSE51
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_MIT0
-rw-r--r--OWNERS1
-rw-r--r--README.md173
-rw-r--r--README.tpl13
-rw-r--r--examples/tcp_accept.rs21
-rw-r--r--src/async_stream.rs69
-rw-r--r--src/lib.rs177
-rw-r--r--src/next.rs32
-rw-r--r--src/yielder.rs87
-rw-r--r--tests/for_await.rs23
-rw-r--r--tests/stream.rs165
-rw-r--r--tests/try_stream.rs80
-rw-r--r--tests/ui/yield_in_async.rs11
-rw-r--r--tests/ui/yield_in_async.stderr76
-rw-r--r--tests/ui/yield_in_closure.rs11
-rw-r--r--tests/ui/yield_in_closure.stderr18
-rw-r--r--tests/ui/yield_in_nested_fn.rs9
-rw-r--r--tests/ui/yield_in_nested_fn.stderr16
25 files changed, 1700 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..29bac5d
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+ "git": {
+ "sha1": "d346ad2d77b11855969b82c9d16bd78ec84e4863"
+ }
+}
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..09ca3df
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,21 @@
+// This file is generated by cargo2android.py --run --dependencies --device.
+
+rust_library {
+ name: "libasync_stream",
+ host_supported: true,
+ crate_name: "async_stream",
+ srcs: ["src/lib.rs"],
+ edition: "2018",
+ rustlibs: [
+ "libfutures_core",
+ ],
+ proc_macros: ["libasync_stream_impl"],
+}
+
+// dependent_library ["feature_list"]
+// async-stream-impl-0.3.0
+// futures-core-0.3.12 "alloc,default,std"
+// proc-macro2-1.0.24 "default,proc-macro"
+// quote-1.0.8 "default,proc-macro"
+// syn-1.0.60 "clone-impls,default,derive,extra-traits,full,parsing,printing,proc-macro,quote,visit-mut"
+// unicode-xid-0.2.1 "default"
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..d924233
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,552 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "arc-swap"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
+
+[[package]]
+name = "async-stream"
+version = "0.3.0"
+dependencies = [
+ "async-stream-impl",
+ "futures-core",
+ "futures-util",
+ "tokio",
+ "tokio-test",
+ "trybuild",
+]
+
+[[package]]
+name = "async-stream-impl"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3548b8efc9f8e8a5a0a2808c5bd8451a9031b9e5b879a79590304ae928b0a70"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "bytes"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "fuchsia-zircon"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+dependencies = [
+ "bitflags",
+ "fuchsia-zircon-sys",
+]
+
+[[package]]
+name = "fuchsia-zircon-sys"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+
+[[package]]
+name = "futures-core"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-task"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "futures-util"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
+dependencies = [
+ "futures-core",
+ "futures-macro",
+ "futures-task",
+ "pin-project",
+ "pin-utils",
+ "proc-macro-hack",
+ "proc-macro-nested",
+ "slab",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "iovec"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+dependencies = [
+ "winapi 0.2.8",
+ "winapi-build",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
+
+[[package]]
+name = "log"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+
+[[package]]
+name = "mio"
+version = "0.6.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
+dependencies = [
+ "cfg-if",
+ "fuchsia-zircon",
+ "fuchsia-zircon-sys",
+ "iovec",
+ "kernel32-sys",
+ "libc",
+ "log",
+ "miow 0.2.1",
+ "net2",
+ "slab",
+ "winapi 0.2.8",
+]
+
+[[package]]
+name = "mio-named-pipes"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
+dependencies = [
+ "log",
+ "mio",
+ "miow 0.3.5",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
+dependencies = [
+ "iovec",
+ "libc",
+ "mio",
+]
+
+[[package]]
+name = "miow"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+dependencies = [
+ "kernel32-sys",
+ "net2",
+ "winapi 0.2.8",
+ "ws2_32-sys",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
+dependencies = [
+ "socket2",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "net2"
+version = "0.2.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
+
+[[package]]
+name = "pin-project"
+version = "0.4.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "0.4.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
+
+[[package]]
+name = "proc-macro-nested"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "serde"
+version = "1.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
+dependencies = [
+ "arc-swap",
+ "libc",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
+
+[[package]]
+name = "socket2"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "tokio"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "iovec",
+ "lazy_static",
+ "libc",
+ "memchr",
+ "mio",
+ "mio-named-pipes",
+ "mio-uds",
+ "num_cpus",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "slab",
+ "tokio-macros",
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio-test"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed0049c119b6d505c4447f5c64873636c7af6c75ab0d45fd9f618d82acb8016d"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "trybuild"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a4d94e6adf00b96b1ab94fcfcd8c3cf916733b39adf90c8f72693629887b9b8"
+dependencies = [
+ "glob",
+ "lazy_static",
+ "serde",
+ "serde_json",
+ "termcolor",
+ "toml",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "winapi"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+
+[[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-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+
+[[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 0.3.9",
+]
+
+[[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 = "ws2_32-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
+dependencies = [
+ "winapi 0.2.8",
+ "winapi-build",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..39573bd
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,40 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "async-stream"
+version = "0.3.0"
+authors = ["Carl Lerche <me@carllerche.com>"]
+description = "Asynchronous streams using async & await notation"
+homepage = "https://github.com/tokio-rs/async-stream"
+documentation = "https://docs.rs/async-stream/0.3.0/async-stream"
+readme = "README.md"
+license = "MIT"
+repository = "https://github.com/tokio-rs/async-stream"
+[dependencies.async-stream-impl]
+version = "0.3.0"
+
+[dependencies.futures-core]
+version = "0.3"
+[dev-dependencies.futures-util]
+version = "0.3"
+
+[dev-dependencies.tokio]
+version = "0.2"
+features = ["full"]
+
+[dev-dependencies.tokio-test]
+version = "0.2"
+
+[dev-dependencies.trybuild]
+version = "1"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..aca3396
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,30 @@
+[package]
+name = "async-stream"
+# When releasing to crates.io:
+# - Update version number
+# - lib.rs: html_root_url.
+# - README.md
+# - Update CHANGELOG.md
+# - Update doc URL.
+# - Cargo.toml
+# - README.md
+# - Create git tag
+version = "0.3.0"
+edition = "2018"
+license = "MIT"
+authors = ["Carl Lerche <me@carllerche.com>"]
+description = "Asynchronous streams using async & await notation"
+documentation = "https://docs.rs/async-stream/0.3.0/async-stream"
+homepage = "https://github.com/tokio-rs/async-stream"
+repository = "https://github.com/tokio-rs/async-stream"
+readme = "README.md"
+
+[dependencies]
+async-stream-impl = { version = "0.3.0", path = "../async-stream-impl" }
+futures-core = "0.3"
+
+[dev-dependencies]
+futures-util = "0.3"
+tokio = { version = "0.2", features = ["full"] }
+tokio-test = "0.2"
+trybuild = "1"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8cbd7d6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,51 @@
+Copyright (c) 2019 Carl Lerche
+
+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.
+
+Copyright (c) 2018 David Tolnay
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..062a50f
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "async-stream"
+description: "Asynchronous streams using async & await notation"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/async-stream"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/async-stream/async-stream-0.3.0.crate"
+ }
+ version: "0.3.0"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2021
+ month: 2
+ day: 8
+ }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..dd36923
--- /dev/null
+++ b/README.md
@@ -0,0 +1,173 @@
+# Asynchronous streams for Rust
+
+Asynchronous stream of elements.
+
+Provides two macros, `stream!` and `try_stream!`, allowing the caller to
+define asynchronous streams of elements. These are implemented using `async`
+& `await` notation. The `stream!` macro works without unstable features.
+
+The `stream!` macro returns an anonymous type implementing the [`Stream`]
+trait. The `Item` associated type is the type of the values yielded from the
+stream. The `try_stream!` also returns an anonymous type implementing the
+[`Stream`] trait, but the `Item` associated type is `Result<T, Error>`. The
+`try_stream!` macro supports using `?` notiation as part of the
+implementation.
+
+## Usage
+
+A basic stream yielding numbers. Values are yielded using the `yield`
+keyword. The stream block must return `()`.
+
+```rust
+use async_stream::stream;
+
+use futures_util::pin_mut;
+use futures_util::stream::StreamExt;
+
+#[tokio::main]
+async fn main() {
+ let s = stream! {
+ for i in 0..3 {
+ yield i;
+ }
+ };
+
+ pin_mut!(s); // needed for iteration
+
+ while let Some(value) = s.next().await {
+ println!("got {}", value);
+ }
+}
+```
+
+Streams may be returned by using `impl Stream<Item = T>`:
+
+```rust
+use async_stream::stream;
+
+use futures_core::stream::Stream;
+use futures_util::pin_mut;
+use futures_util::stream::StreamExt;
+
+fn zero_to_three() -> impl Stream<Item = u32> {
+ stream! {
+ for i in 0..3 {
+ yield i;
+ }
+ }
+}
+
+#[tokio::main]
+async fn main() {
+ let s = zero_to_three();
+ pin_mut!(s); // needed for iteration
+
+ while let Some(value) = s.next().await {
+ println!("got {}", value);
+ }
+}
+```
+
+Streams may be implemented in terms of other streams:
+
+```rust
+use async_stream::stream;
+
+use futures_core::stream::Stream;
+use futures_util::pin_mut;
+use futures_util::stream::StreamExt;
+
+fn zero_to_three() -> impl Stream<Item = u32> {
+ stream! {
+ for i in 0..3 {
+ yield i;
+ }
+ }
+}
+
+fn double<S: Stream<Item = u32>>(input: S)
+ -> impl Stream<Item = u32>
+{
+ stream! {
+ pin_mut!(input);
+ while let Some(value) = input.next().await {
+ yield value * 2;
+ }
+ }
+}
+
+#[tokio::main]
+async fn main() {
+ let s = double(zero_to_three());
+ pin_mut!(s); // needed for iteration
+
+ while let Some(value) = s.next().await {
+ println!("got {}", value);
+ }
+}
+```
+
+Rust try notation (`?`) can be used with the `try_stream!` macro. The `Item`
+of the returned stream is `Result` with `Ok` being the value yielded and
+`Err` the error type returned by `?`.
+
+```rust
+use tokio::net::{TcpListener, TcpStream};
+
+use async_stream::try_stream;
+use futures_core::stream::Stream;
+
+use std::io;
+use std::net::SocketAddr;
+
+fn bind_and_accept(addr: SocketAddr)
+ -> impl Stream<Item = io::Result<TcpStream>>
+{
+ try_stream! {
+ let mut listener = TcpListener::bind(&addr)?;
+
+ loop {
+ let (stream, addr) = listener.accept().await?;
+ println!("received on {:?}", addr);
+ yield stream;
+ }
+ }
+}
+```
+
+## Implementation
+
+The `stream!` and `try_stream!` macros are implemented using proc macros.
+Given that proc macros in expression position are not supported on stable
+rust, a hack similar to the one provided by the [`proc-macro-hack`] crate is
+used. The macro searches the syntax tree for instances of `sender.send($expr)` and
+transforms them into `sender.send($expr).await`.
+
+The stream uses a lightweight sender to send values from the stream
+implementation to the caller. When entering the stream, an `Option<T>` is
+stored on the stack. A pointer to the cell is stored in a thread local and
+`poll` is called on the async block. When `poll` returns.
+`sender.send(value)` stores the value that cell and yields back to the
+caller.
+
+## Limitations
+
+`async-stream` suffers from the same limitations as the [`proc-macro-hack`]
+crate. Primarily, nesting support must be implemented using a `TT-muncher`.
+If large `stream!` blocks are used, the caller will be required to add
+`#![recursion_limit = "..."]` to their crate.
+
+A `stream!` macro may only contain up to 64 macro invocations.
+
+[`Stream`]: https://docs.rs/futures-core/*/futures_core/stream/trait.Stream.html
+[`proc-macro-hack`]: https://github.com/dtolnay/proc-macro-hack/
+
+## License
+
+This project is licensed under the [MIT license](LICENSE).
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in `async-stream` by you, shall be licensed as MIT, without any
+additional terms or conditions.
diff --git a/README.tpl b/README.tpl
new file mode 100644
index 0000000..cf0b729
--- /dev/null
+++ b/README.tpl
@@ -0,0 +1,13 @@
+# Asynchronous streams for Rust
+
+{{readme}}
+
+## License
+
+This project is licensed under the [MIT license](LICENSE).
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in `async-stream` by you, shall be licensed as MIT, without any
+additional terms or conditions.
diff --git a/examples/tcp_accept.rs b/examples/tcp_accept.rs
new file mode 100644
index 0000000..023e1a1
--- /dev/null
+++ b/examples/tcp_accept.rs
@@ -0,0 +1,21 @@
+use async_stream::stream;
+use futures_util::pin_mut;
+use futures_util::stream::StreamExt;
+use tokio::net::TcpListener;
+
+#[tokio::main]
+async fn main() {
+ let mut listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
+
+ let incoming = stream! {
+ loop {
+ let (socket, _) = listener.accept().await.unwrap();
+ yield socket;
+ }
+ };
+ pin_mut!(incoming);
+
+ while let Some(v) = incoming.next().await {
+ println!("handle = {:?}", v);
+ }
+}
diff --git a/src/async_stream.rs b/src/async_stream.rs
new file mode 100644
index 0000000..30115df
--- /dev/null
+++ b/src/async_stream.rs
@@ -0,0 +1,69 @@
+use crate::yielder::Receiver;
+
+use futures_core::{FusedStream, Stream};
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct AsyncStream<T, U> {
+ rx: Receiver<T>,
+ done: bool,
+ generator: U,
+}
+
+impl<T, U> AsyncStream<T, U> {
+ #[doc(hidden)]
+ pub fn new(rx: Receiver<T>, generator: U) -> AsyncStream<T, U> {
+ AsyncStream {
+ rx,
+ done: false,
+ generator,
+ }
+ }
+}
+
+impl<T, U> FusedStream for AsyncStream<T, U>
+where
+ U: Future<Output = ()>,
+{
+ fn is_terminated(&self) -> bool {
+ self.done
+ }
+}
+
+impl<T, U> Stream for AsyncStream<T, U>
+where
+ U: Future<Output = ()>,
+{
+ type Item = T;
+
+ fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+ unsafe {
+ let me = Pin::get_unchecked_mut(self);
+
+ if me.done {
+ return Poll::Ready(None);
+ }
+
+ let mut dst = None;
+ let res = {
+ let _enter = me.rx.enter(&mut dst);
+ Pin::new_unchecked(&mut me.generator).poll(cx)
+ };
+
+ me.done = res.is_ready();
+
+ if dst.is_some() {
+ return Poll::Ready(dst.take());
+ }
+
+ if me.done {
+ Poll::Ready(None)
+ } else {
+ Poll::Pending
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..9906677
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,177 @@
+#![doc(html_root_url = "https://docs.rs/async-stream/0.3.0")]
+#![warn(
+ missing_debug_implementations,
+ missing_docs,
+ rust_2018_idioms,
+ unreachable_pub
+)]
+#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]
+
+//! Asynchronous stream of elements.
+//!
+//! Provides two macros, `stream!` and `try_stream!`, allowing the caller to
+//! define asynchronous streams of elements. These are implemented using `async`
+//! & `await` notation. The `stream!` macro works without unstable features.
+//!
+//! The `stream!` macro returns an anonymous type implementing the [`Stream`]
+//! trait. The `Item` associated type is the type of the values yielded from the
+//! stream. The `try_stream!` also returns an anonymous type implementing the
+//! [`Stream`] trait, but the `Item` associated type is `Result<T, Error>`. The
+//! `try_stream!` macro supports using `?` notiation as part of the
+//! implementation.
+//!
+//! # Usage
+//!
+//! A basic stream yielding numbers. Values are yielded using the `yield`
+//! keyword. The stream block must return `()`.
+//!
+//! ```rust
+//! use async_stream::stream;
+//!
+//! use futures_util::pin_mut;
+//! use futures_util::stream::StreamExt;
+//!
+//! #[tokio::main]
+//! async fn main() {
+//! let s = stream! {
+//! for i in 0..3 {
+//! yield i;
+//! }
+//! };
+//!
+//! pin_mut!(s); // needed for iteration
+//!
+//! while let Some(value) = s.next().await {
+//! println!("got {}", value);
+//! }
+//! }
+//! ```
+//!
+//! Streams may be returned by using `impl Stream<Item = T>`:
+//!
+//! ```rust
+//! use async_stream::stream;
+//!
+//! use futures_core::stream::Stream;
+//! use futures_util::pin_mut;
+//! use futures_util::stream::StreamExt;
+//!
+//! fn zero_to_three() -> impl Stream<Item = u32> {
+//! stream! {
+//! for i in 0..3 {
+//! yield i;
+//! }
+//! }
+//! }
+//!
+//! #[tokio::main]
+//! async fn main() {
+//! let s = zero_to_three();
+//! pin_mut!(s); // needed for iteration
+//!
+//! while let Some(value) = s.next().await {
+//! println!("got {}", value);
+//! }
+//! }
+//! ```
+//!
+//! Streams may be implemented in terms of other streams:
+//!
+//! ```rust
+//! use async_stream::stream;
+//!
+//! use futures_core::stream::Stream;
+//! use futures_util::pin_mut;
+//! use futures_util::stream::StreamExt;
+//!
+//! fn zero_to_three() -> impl Stream<Item = u32> {
+//! stream! {
+//! for i in 0..3 {
+//! yield i;
+//! }
+//! }
+//! }
+//!
+//! fn double<S: Stream<Item = u32>>(input: S)
+//! -> impl Stream<Item = u32>
+//! {
+//! stream! {
+//! pin_mut!(input);
+//! while let Some(value) = input.next().await {
+//! yield value * 2;
+//! }
+//! }
+//! }
+//!
+//! #[tokio::main]
+//! async fn main() {
+//! let s = double(zero_to_three());
+//! pin_mut!(s); // needed for iteration
+//!
+//! while let Some(value) = s.next().await {
+//! println!("got {}", value);
+//! }
+//! }
+//! ```
+//!
+//! Rust try notation (`?`) can be used with the `try_stream!` macro. The `Item`
+//! of the returned stream is `Result` with `Ok` being the value yielded and
+//! `Err` the error type returned by `?`.
+//!
+//! ```rust
+//! use tokio::net::{TcpListener, TcpStream};
+//!
+//! use async_stream::try_stream;
+//! use futures_core::stream::Stream;
+//!
+//! use std::io;
+//! use std::net::SocketAddr;
+//!
+//! fn bind_and_accept(addr: SocketAddr)
+//! -> impl Stream<Item = io::Result<TcpStream>>
+//! {
+//! try_stream! {
+//! let mut listener = TcpListener::bind(addr).await?;
+//!
+//! loop {
+//! let (stream, addr) = listener.accept().await?;
+//! println!("received on {:?}", addr);
+//! yield stream;
+//! }
+//! }
+//! }
+//! ```
+//!
+//! # Implementation
+//!
+//! The `stream!` and `try_stream!` macros are implemented using proc macros.
+//! Given that proc macros in expression position are not supported on stable
+//! rust, a hack similar to the one provided by the [`proc-macro-hack`] crate is
+//! used. The macro searches the syntax tree for instances of `sender.send($expr)` and
+//! transforms them into `sender.send($expr).await`.
+//!
+//! The stream uses a lightweight sender to send values from the stream
+//! implementation to the caller. When entering the stream, an `Option<T>` is
+//! stored on the stack. A pointer to the cell is stored in a thread local and
+//! `poll` is called on the async block. When `poll` returns.
+//! `sender.send(value)` stores the value that cell and yields back to the
+//! caller.
+//!
+//! [`Stream`]: https://docs.rs/futures-core/*/futures_core/stream/trait.Stream.html
+
+mod async_stream;
+mod next;
+#[doc(hidden)]
+pub mod yielder;
+
+// Used by the macro, but not intended to be accessed publically.
+#[doc(hidden)]
+pub use crate::async_stream::AsyncStream;
+
+pub use async_stream_impl::{stream, try_stream};
+
+#[doc(hidden)]
+pub mod reexport {
+ #[doc(hidden)]
+ pub use crate::next::next;
+}
diff --git a/src/next.rs b/src/next.rs
new file mode 100644
index 0000000..7b1e046
--- /dev/null
+++ b/src/next.rs
@@ -0,0 +1,32 @@
+use futures_core::Stream;
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+// This is equivalent to the `futures::StreamExt::next` method.
+// But we want to make this crate dependency as small as possible, so we define our `next` function.
+#[doc(hidden)]
+pub fn next<S>(stream: &mut S) -> impl Future<Output = Option<S::Item>> + '_
+where
+ S: Stream + Unpin,
+{
+ Next { stream }
+}
+
+#[derive(Debug)]
+struct Next<'a, S> {
+ stream: &'a mut S,
+}
+
+impl<S> Unpin for Next<'_, S> where S: Unpin {}
+
+impl<S> Future for Next<'_, S>
+where
+ S: Stream + Unpin,
+{
+ type Output = Option<S::Item>;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ Pin::new(&mut self.stream).poll_next(cx)
+ }
+}
diff --git a/src/yielder.rs b/src/yielder.rs
new file mode 100644
index 0000000..49c4133
--- /dev/null
+++ b/src/yielder.rs
@@ -0,0 +1,87 @@
+use std::cell::Cell;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::ptr;
+use std::task::{Context, Poll};
+
+#[derive(Debug)]
+pub struct Sender<T> {
+ _p: PhantomData<T>,
+}
+
+#[derive(Debug)]
+pub struct Receiver<T> {
+ _p: PhantomData<T>,
+}
+
+pub(crate) struct Enter<'a, T> {
+ _rx: &'a mut Receiver<T>,
+ prev: *mut (),
+}
+
+pub fn pair<T>() -> (Sender<T>, Receiver<T>) {
+ let tx = Sender { _p: PhantomData };
+ let rx = Receiver { _p: PhantomData };
+ (tx, rx)
+}
+
+// Tracks the pointer to `Option<T>`.
+//
+// TODO: Ensure wakers match?
+thread_local!(static STORE: Cell<*mut ()> = Cell::new(ptr::null_mut()));
+
+// ===== impl Sender =====
+
+impl<T: Unpin> Sender<T> {
+ pub fn send(&mut self, value: T) -> impl Future<Output = ()> {
+ Send { value: Some(value) }
+ }
+}
+
+struct Send<T> {
+ value: Option<T>,
+}
+
+impl<T: Unpin> Future for Send<T> {
+ type Output = ();
+
+ fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> {
+ if self.value.is_none() {
+ return Poll::Ready(());
+ }
+
+ STORE.with(|cell| unsafe {
+ let ptr = cell.get() as *mut Option<T>;
+ let option_ref = ptr.as_mut().expect("invalid usage");
+
+ if option_ref.is_none() {
+ *option_ref = self.value.take();
+ }
+
+ Poll::Pending
+ })
+ }
+}
+
+// ===== impl Receiver =====
+
+impl<T> Receiver<T> {
+ pub(crate) fn enter<'a>(&'a mut self, dst: &'a mut Option<T>) -> Enter<'a, T> {
+ let prev = STORE.with(|cell| {
+ let prev = cell.get();
+ cell.set(dst as *mut _ as *mut ());
+ prev
+ });
+
+ Enter { _rx: self, prev }
+ }
+}
+
+// ===== impl Enter =====
+
+impl<'a, T> Drop for Enter<'a, T> {
+ fn drop(&mut self) {
+ STORE.with(|cell| cell.set(self.prev));
+ }
+}
diff --git a/tests/for_await.rs b/tests/for_await.rs
new file mode 100644
index 0000000..590ffbd
--- /dev/null
+++ b/tests/for_await.rs
@@ -0,0 +1,23 @@
+use async_stream::stream;
+
+use futures_util::stream::StreamExt;
+
+#[tokio::test]
+async fn test() {
+ let s = stream! {
+ yield "hello";
+ yield "world";
+ };
+
+ let s = stream! {
+ for await x in s {
+ yield x.to_owned() + "!";
+ }
+ };
+
+ let values: Vec<_> = s.collect().await;
+
+ assert_eq!(2, values.len());
+ assert_eq!("hello!", values[0]);
+ assert_eq!("world!", values[1]);
+}
diff --git a/tests/stream.rs b/tests/stream.rs
new file mode 100644
index 0000000..e46fc5a
--- /dev/null
+++ b/tests/stream.rs
@@ -0,0 +1,165 @@
+use async_stream::stream;
+
+use futures_core::stream::{FusedStream, Stream};
+use futures_util::pin_mut;
+use futures_util::stream::StreamExt;
+use tokio::sync::mpsc;
+use tokio_test::assert_ok;
+
+#[tokio::test]
+async fn noop_stream() {
+ let s = stream! {};
+ pin_mut!(s);
+
+ while let Some(_) = s.next().await {
+ unreachable!();
+ }
+}
+
+#[tokio::test]
+async fn empty_stream() {
+ let mut ran = false;
+
+ {
+ let r = &mut ran;
+ let s = stream! {
+ *r = true;
+ println!("hello world!");
+ };
+ pin_mut!(s);
+
+ while let Some(_) = s.next().await {
+ unreachable!();
+ }
+ }
+
+ assert!(ran);
+}
+
+#[tokio::test]
+async fn yield_single_value() {
+ let s = stream! {
+ yield "hello";
+ };
+
+ let values: Vec<_> = s.collect().await;
+
+ assert_eq!(1, values.len());
+ assert_eq!("hello", values[0]);
+}
+
+#[tokio::test]
+async fn fused() {
+ let s = stream! {
+ yield "hello";
+ };
+ pin_mut!(s);
+
+ assert!(!s.is_terminated());
+ assert_eq!(s.next().await, Some("hello"));
+ assert_eq!(s.next().await, None);
+
+ assert!(s.is_terminated());
+ // This should return None from now on
+ assert_eq!(s.next().await, None);
+}
+
+#[tokio::test]
+async fn yield_multi_value() {
+ let s = stream! {
+ yield "hello";
+ yield "world";
+ yield "dizzy";
+ };
+
+ let values: Vec<_> = s.collect().await;
+
+ assert_eq!(3, values.len());
+ assert_eq!("hello", values[0]);
+ assert_eq!("world", values[1]);
+ assert_eq!("dizzy", values[2]);
+}
+
+#[tokio::test]
+async fn return_stream() {
+ fn build_stream() -> impl Stream<Item = u32> {
+ stream! {
+ yield 1;
+ yield 2;
+ yield 3;
+ }
+ }
+
+ let s = build_stream();
+
+ let values: Vec<_> = s.collect().await;
+ assert_eq!(3, values.len());
+ assert_eq!(1, values[0]);
+ assert_eq!(2, values[1]);
+ assert_eq!(3, values[2]);
+}
+
+#[tokio::test]
+async fn consume_channel() {
+ let (mut tx, mut rx) = mpsc::channel(10);
+
+ let s = stream! {
+ while let Some(v) = rx.recv().await {
+ yield v;
+ }
+ };
+
+ pin_mut!(s);
+
+ for i in 0..3 {
+ assert_ok!(tx.send(i).await);
+ assert_eq!(Some(i), s.next().await);
+ }
+
+ drop(tx);
+ assert_eq!(None, s.next().await);
+}
+
+#[tokio::test]
+async fn borrow_self() {
+ struct Data(String);
+
+ impl Data {
+ fn stream<'a>(&'a self) -> impl Stream<Item = &str> + 'a {
+ stream! {
+ yield &self.0[..];
+ }
+ }
+ }
+
+ let data = Data("hello".to_string());
+ let s = data.stream();
+ pin_mut!(s);
+
+ assert_eq!(Some("hello"), s.next().await);
+}
+
+#[tokio::test]
+async fn stream_in_stream() {
+ let s = stream! {
+ let s = stream! {
+ for i in 0..3 {
+ yield i;
+ }
+ };
+
+ pin_mut!(s);
+ while let Some(v) = s.next().await {
+ yield v;
+ }
+ };
+
+ let values: Vec<_> = s.collect().await;
+ assert_eq!(3, values.len());
+}
+
+#[test]
+fn test() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/tests/try_stream.rs b/tests/try_stream.rs
new file mode 100644
index 0000000..063e37a
--- /dev/null
+++ b/tests/try_stream.rs
@@ -0,0 +1,80 @@
+use async_stream::try_stream;
+
+use futures_core::stream::Stream;
+use futures_util::stream::StreamExt;
+
+#[tokio::test]
+async fn single_err() {
+ let s = try_stream! {
+ if true {
+ Err("hello")?;
+ } else {
+ yield "world";
+ }
+
+ unreachable!();
+ };
+
+ let values: Vec<_> = s.collect().await;
+ assert_eq!(1, values.len());
+ assert_eq!(Err("hello"), values[0]);
+}
+
+#[tokio::test]
+async fn yield_then_err() {
+ let s = try_stream! {
+ yield "hello";
+ Err("world")?;
+ unreachable!();
+ };
+
+ let values: Vec<_> = s.collect().await;
+ assert_eq!(2, values.len());
+ assert_eq!(Ok("hello"), values[0]);
+ assert_eq!(Err("world"), values[1]);
+}
+
+#[tokio::test]
+async fn convert_err() {
+ struct ErrorA(u8);
+ #[derive(PartialEq, Debug)]
+ struct ErrorB(u8);
+ impl From<ErrorA> for ErrorB {
+ fn from(a: ErrorA) -> ErrorB {
+ ErrorB(a.0)
+ }
+ }
+
+ fn test() -> impl Stream<Item = Result<&'static str, ErrorB>> {
+ try_stream! {
+ if true {
+ Err(ErrorA(1))?;
+ } else {
+ Err(ErrorB(2))?;
+ }
+ yield "unreachable";
+ }
+ }
+
+ let values: Vec<_> = test().collect().await;
+ assert_eq!(1, values.len());
+ assert_eq!(Err(ErrorB(1)), values[0]);
+}
+
+#[tokio::test]
+async fn multi_try() {
+ fn test() -> impl Stream<Item = Result<i32, String>> {
+ try_stream! {
+ let a = Ok::<_, String>(Ok::<_, String>(123))??;
+ for _ in (1..10) {
+ yield a;
+ }
+ }
+ }
+ let values: Vec<_> = test().collect().await;
+ assert_eq!(9, values.len());
+ assert_eq!(
+ std::iter::repeat(123).take(9).map(Ok).collect::<Vec<_>>(),
+ values
+ );
+}
diff --git a/tests/ui/yield_in_async.rs b/tests/ui/yield_in_async.rs
new file mode 100644
index 0000000..24e7330
--- /dev/null
+++ b/tests/ui/yield_in_async.rs
@@ -0,0 +1,11 @@
+use async_stream::stream;
+
+fn main() {
+ stream! {
+ let f = async {
+ yield 123;
+ };
+
+ let v = f.await;
+ };
+}
diff --git a/tests/ui/yield_in_async.stderr b/tests/ui/yield_in_async.stderr
new file mode 100644
index 0000000..1e9d8ff
--- /dev/null
+++ b/tests/ui/yield_in_async.stderr
@@ -0,0 +1,76 @@
+error[E0658]: yield syntax is experimental
+ --> $DIR/yield_in_async.rs:6:13
+ |
+6 | yield 123;
+ | ^^^^^^^^^
+ |
+ = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
+
+error[E0727]: `async` generators are not yet supported
+ --> $DIR/yield_in_async.rs:6:13
+ |
+6 | yield 123;
+ | ^^^^^^^^^
+
+error[E0271]: type mismatch resolving `<[static generator@$DIR/tests/ui/yield_in_async.rs:4:5: 10:7 _] as std::ops::Generator<std::future::ResumeTy>>::Yield == ()`
+ --> $DIR/yield_in_async.rs:4:5
+ |
+4 | / stream! {
+5 | | let f = async {
+6 | | yield 123;
+7 | | };
+8 | |
+9 | | let v = f.await;
+10 | | };
+ | |______^ expected `()`, found integer
+
+error[E0698]: type inside `async` block must be known in this context
+ --> $DIR/yield_in_async.rs:6:19
+ |
+6 | yield 123;
+ | ^^^ cannot infer type for type `{integer}`
+ |
+note: the type is part of the `async` block because of this `yield`
+ --> $DIR/yield_in_async.rs:6:13
+ |
+6 | yield 123;
+ | ^^^^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+ --> $DIR/yield_in_async.rs:5:13
+ |
+5 | let f = async {
+ | ^ cannot infer type for type `{integer}`
+ |
+note: the type is part of the `async` block because of this `await`
+ --> $DIR/yield_in_async.rs:9:17
+ |
+9 | let v = f.await;
+ | ^^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+ --> $DIR/yield_in_async.rs:9:17
+ |
+9 | let v = f.await;
+ | ^ cannot infer type for type `{integer}`
+ |
+note: the type is part of the `async` block because of this `await`
+ --> $DIR/yield_in_async.rs:9:17
+ |
+9 | let v = f.await;
+ | ^^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+ --> $DIR/yield_in_async.rs:9:17
+ |
+9 | let v = f.await;
+ | ^^^^^^^ cannot infer type for type `{integer}`
+ |
+note: the type is part of the `async` block because of this `await`
+ --> $DIR/yield_in_async.rs:9:17
+ |
+9 | let v = f.await;
+ | ^^^^^^^
+
+Some errors have detailed explanations: E0271, E0658, E0698, E0727.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/yield_in_closure.rs b/tests/ui/yield_in_closure.rs
new file mode 100644
index 0000000..cd6ebd9
--- /dev/null
+++ b/tests/ui/yield_in_closure.rs
@@ -0,0 +1,11 @@
+use async_stream::stream;
+
+fn main() {
+ stream! {
+ Ok("value")
+ .and_then(|v| {
+ yield v;
+ Ok(())
+ });
+ };
+}
diff --git a/tests/ui/yield_in_closure.stderr b/tests/ui/yield_in_closure.stderr
new file mode 100644
index 0000000..77092e0
--- /dev/null
+++ b/tests/ui/yield_in_closure.stderr
@@ -0,0 +1,18 @@
+error[E0658]: yield syntax is experimental
+ --> $DIR/yield_in_closure.rs:7:17
+ |
+7 | yield v;
+ | ^^^^^^^
+ |
+ = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
+
+error[E0277]: expected a `std::ops::FnOnce<(&str,)>` closure, found `[generator@$DIR/tests/ui/yield_in_closure.rs:4:5: 10:7 _]`
+ --> $DIR/yield_in_closure.rs:6:14
+ |
+6 | .and_then(|v| {
+ | ^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `[generator@$DIR/tests/ui/yield_in_closure.rs:4:5: 10:7 _]`
+ |
+ = help: the trait `std::ops::FnOnce<(&str,)>` is not implemented for `[generator@$DIR/tests/ui/yield_in_closure.rs:4:5: 10:7 _]`
+
+Some errors have detailed explanations: E0277, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/yield_in_nested_fn.rs b/tests/ui/yield_in_nested_fn.rs
new file mode 100644
index 0000000..9ae6cf2
--- /dev/null
+++ b/tests/ui/yield_in_nested_fn.rs
@@ -0,0 +1,9 @@
+use async_stream::stream;
+
+fn main() {
+ stream! {
+ fn foo() {
+ yield "hello";
+ }
+ };
+}
diff --git a/tests/ui/yield_in_nested_fn.stderr b/tests/ui/yield_in_nested_fn.stderr
new file mode 100644
index 0000000..a562555
--- /dev/null
+++ b/tests/ui/yield_in_nested_fn.stderr
@@ -0,0 +1,16 @@
+error[E0658]: yield syntax is experimental
+ --> $DIR/yield_in_nested_fn.rs:6:13
+ |
+6 | yield "hello";
+ | ^^^^^^^^^^^^^
+ |
+ = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
+
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/yield_in_nested_fn.rs:6:13
+ |
+6 | yield "hello";
+ | ^^^^^^^^^^^^^
+
+Some errors have detailed explanations: E0627, E0658.
+For more information about an error, try `rustc --explain E0627`.