{"id":13671786,"url":"https://github.com/taiki-e/futures-async-stream","last_synced_at":"2026-01-08T16:07:24.720Z","repository":{"id":37664555,"uuid":"199863976","full_name":"taiki-e/futures-async-stream","owner":"taiki-e","description":"Async stream for Rust and the futures crate.","archived":false,"fork":false,"pushed_at":"2025-05-05T05:44:51.000Z","size":764,"stargazers_count":183,"open_issues_count":3,"forks_count":8,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-05-05T06:34:02.214Z","etag":null,"topics":["asynchronous","no-std","proc-macro","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/futures-async-stream","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/taiki-e.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"taiki-e"}},"created_at":"2019-07-31T13:41:14.000Z","updated_at":"2025-05-05T05:44:54.000Z","dependencies_parsed_at":"2024-01-12T18:03:58.909Z","dependency_job_id":"ea776212-bd0a-471d-839e-56449c6a3116","html_url":"https://github.com/taiki-e/futures-async-stream","commit_stats":{"total_commits":613,"total_committers":5,"mean_commits":122.6,"dds":0.00815660685154973,"last_synced_commit":"a004fb00125f399eb26d675378ddb29af066583a"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taiki-e%2Ffutures-async-stream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taiki-e%2Ffutures-async-stream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taiki-e%2Ffutures-async-stream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/taiki-e%2Ffutures-async-stream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/taiki-e","download_url":"https://codeload.github.com/taiki-e/futures-async-stream/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310513,"owners_count":22049468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","no-std","proc-macro","rust"],"created_at":"2024-08-02T09:01:18.667Z","updated_at":"2026-01-08T16:07:24.714Z","avatar_url":"https://github.com/taiki-e.png","language":"Rust","funding_links":["https://github.com/sponsors/taiki-e"],"categories":["Rust"],"sub_categories":[],"readme":"# futures-async-stream\n\n[![crates.io](https://img.shields.io/crates/v/futures-async-stream?style=flat-square\u0026logo=rust)](https://crates.io/crates/futures-async-stream)\n[![docs.rs](https://img.shields.io/badge/docs.rs-futures--async--stream-blue?style=flat-square\u0026logo=docs.rs)](https://docs.rs/futures-async-stream)\n[![license](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue?style=flat-square)](#license)\n[![github actions](https://img.shields.io/github/actions/workflow/status/taiki-e/futures-async-stream/ci.yml?branch=main\u0026style=flat-square\u0026logo=github)](https://github.com/taiki-e/futures-async-stream/actions)\n\n\u003c!-- tidy:sync-markdown-to-rustdoc:start:src/lib.rs --\u003e\n\nAsync stream for Rust and the futures crate.\n\nThis crate provides useful features for streams, using `async_await` and\nunstable [`coroutines`](https://github.com/rust-lang/rust/issues/43122).\n\n## Usage\n\nAdd this to your `Cargo.toml`:\n\n```toml\n[dependencies]\nfutures-async-stream = \"0.2\"\nfutures = \"0.3\"\n```\n\n*Compiler support: requires rustc nightly-2024-04-25+*\n\n## `#[for_await]`\n\nProcesses streams using a for loop.\n\nThis is a reimplement of [futures-await]'s `#[async]` for loops for\nfutures 0.3 and is an experimental implementation of [the idea listed as the\nnext step of async/await](https://rust-lang.github.io/rfcs/2394-async_await.html#for-await-and-processing-streams).\n\n```rust\n#![feature(proc_macro_hygiene, stmt_expr_attributes)]\n\nuse futures::stream::Stream;\nuse futures_async_stream::for_await;\n\nasync fn collect(stream: impl Stream\u003cItem = i32\u003e) -\u003e Vec\u003ci32\u003e {\n    let mut vec = vec![];\n    #[for_await]\n    for value in stream {\n        vec.push(value);\n    }\n    vec\n}\n```\n\n`value` has the `Item` type of the stream passed in. Note that async for\nloops can only be used inside of `async` functions, closures, blocks,\n`#[stream]` functions and `stream_block!` macros.\n\n## `#[stream]`\n\nCreates streams via coroutines.\n\nThis is a reimplement of [futures-await]'s `#[stream]` for futures 0.3 and\nis an experimental implementation of [the idea listed as the next step of\nasync/await](https://rust-lang.github.io/rfcs/2394-async_await.html#generators-and-streams).\n\n```rust\n#![feature(coroutines)]\n\nuse futures::stream::Stream;\nuse futures_async_stream::stream;\n\n// Returns a stream of i32\n#[stream(item = i32)]\nasync fn foo(stream: impl Stream\u003cItem = String\u003e) {\n    // `for_await` is built into `stream`. If you use `for_await` only in `stream`, there is no need to import `for_await`.\n    #[for_await]\n    for x in stream {\n        yield x.parse().unwrap();\n    }\n}\n```\n\nTo early exit from a `#[stream]` function or block, use `return`.\n\n`#[stream]` on async fn must have an item type specified via\n`item = some::Path` and the values output from the stream must be yielded\nvia the `yield` expression.\n\n`#[stream]` can also be used on async blocks:\n\n```rust\n#![feature(coroutines, proc_macro_hygiene, stmt_expr_attributes)]\n\nuse futures::stream::Stream;\nuse futures_async_stream::stream;\n\nfn foo() -\u003e impl Stream\u003cItem = i32\u003e {\n    #[stream]\n    async move {\n        for i in 0..10 {\n            yield i;\n        }\n    }\n}\n```\n\nNote that `#[stream]` on async block does not require the `item` argument,\nbut it may require additional type annotations.\n\n## Using async stream functions in traits\n\nYou can use async stream functions in traits by passing `boxed` or\n`boxed_local` as an argument.\n\n```rust\n#![feature(coroutines)]\n\nuse futures_async_stream::stream;\n\ntrait Foo {\n    #[stream(boxed, item = u32)]\n    async fn method(\u0026mut self);\n}\n\nstruct Bar(u32);\n\nimpl Foo for Bar {\n    #[stream(boxed, item = u32)]\n    async fn method(\u0026mut self) {\n        while self.0 \u003c u32::MAX {\n            self.0 += 1;\n            yield self.0;\n        }\n    }\n}\n```\n\nA async stream function that received a `boxed` argument is converted to a\nfunction that returns `Pin\u003cBox\u003cdyn Stream\u003cItem = item\u003e + Send + 'lifetime\u003e\u003e`.\nIf you passed `boxed_local` instead of `boxed`, async stream function\nreturns a non-thread-safe stream (`Pin\u003cBox\u003cdyn Stream\u003cItem = item\u003e + 'lifetime\u003e\u003e`).\n\n```rust\n#![feature(coroutines)]\n\nuse std::pin::Pin;\n\nuse futures::stream::Stream;\nuse futures_async_stream::stream;\n\n// The trait itself can be defined without unstable features.\ntrait Foo {\n    fn method(\u0026mut self) -\u003e Pin\u003cBox\u003cdyn Stream\u003cItem = u32\u003e + Send + '_\u003e\u003e;\n}\n\nstruct Bar(u32);\n\nimpl Foo for Bar {\n    #[stream(boxed, item = u32)]\n    async fn method(\u0026mut self) {\n        while self.0 \u003c u32::MAX {\n            self.0 += 1;\n            yield self.0;\n        }\n    }\n}\n```\n\n## `#[try_stream]`\n\n`?` operator can be used with the `#[try_stream]`. The `Item` of the\nreturned stream is `Result` with `Ok` being the value yielded and `Err` the\nerror type returned by `?` operator or `return Err(...)`.\n\n```rust\n#![feature(coroutines)]\n\nuse futures::stream::Stream;\nuse futures_async_stream::try_stream;\n\n#[try_stream(ok = i32, error = Box\u003cdyn std::error::Error\u003e)]\nasync fn foo(stream: impl Stream\u003cItem = String\u003e) {\n    #[for_await]\n    for x in stream {\n        yield x.parse()?;\n    }\n}\n```\n\n`#[try_stream]` can be used wherever `#[stream]` can be used.\n\nTo early exit from a `#[try_stream]` function or block, use `return Ok(())`.\n\n\u003c!--\n## List of features that may be added in the future as an extension of this feature:\n\n- `async_sink` (https://github.com/rust-lang-nursery/futures-rs/pull/1548#issuecomment-486205382)\n- Support `.await` in macro (https://github.com/rust-lang-nursery/futures-rs/pull/1548#discussion_r285341883)\n- Parallel version of `for_await` (https://github.com/rustasync/runtime/pull/25)\n--\u003e\n\n## How to write the equivalent code without this API?\n\n### `#[for_await]`\n\nYou can write this by combining `while let` loop, `.await`, `pin!` macro,\nand `StreamExt::next()` method:\n\n```rust\nuse std::pin::pin;\n\nuse futures::stream::{Stream, StreamExt};\n\nasync fn collect(stream: impl Stream\u003cItem = i32\u003e) -\u003e Vec\u003ci32\u003e {\n    let mut vec = vec![];\n    let mut stream = pin!(stream);\n    while let Some(value) = stream.next().await {\n        vec.push(value);\n    }\n    vec\n}\n```\n\n### `#[stream]`\n\nYou can write this by manually implementing the combinator:\n\n```rust\nuse std::{\n    pin::Pin,\n    task::{ready, Context, Poll},\n};\n\nuse futures::stream::Stream;\nuse pin_project::pin_project;\n\nfn foo\u003cS\u003e(stream: S) -\u003e impl Stream\u003cItem = i32\u003e\nwhere\n    S: Stream\u003cItem = String\u003e,\n{\n    Foo { stream }\n}\n\n#[pin_project]\nstruct Foo\u003cS\u003e {\n    #[pin]\n    stream: S,\n}\n\nimpl\u003cS\u003e Stream for Foo\u003cS\u003e\nwhere\n    S: Stream\u003cItem = String\u003e,\n{\n    type Item = i32;\n\n    fn poll_next(self: Pin\u003c\u0026mut Self\u003e, cx: \u0026mut Context\u003c'_\u003e) -\u003e Poll\u003cOption\u003cSelf::Item\u003e\u003e {\n        if let Some(x) = ready!(self.project().stream.poll_next(cx)) {\n            Poll::Ready(Some(x.parse().unwrap()))\n        } else {\n            Poll::Ready(None)\n        }\n    }\n}\n```\n\n[futures-await]: https://github.com/alexcrichton/futures-await\n\n\u003c!-- tidy:sync-markdown-to-rustdoc:end --\u003e\n\n## License\n\nLicensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or\n[MIT license](LICENSE-MIT) at your option.\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall\nbe dual licensed as above, without any additional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaiki-e%2Ffutures-async-stream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftaiki-e%2Ffutures-async-stream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftaiki-e%2Ffutures-async-stream/lists"}