{"id":22294799,"url":"https://github.com/scouten/async-generic","last_synced_at":"2025-07-29T01:31:38.439Z","repository":{"id":196218751,"uuid":"694908347","full_name":"scouten/async-generic","owner":"scouten","description":"Write code that can be both async and synchronous without duplicating it","archived":false,"fork":false,"pushed_at":"2024-09-28T21:15:21.000Z","size":53,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-29T09:43:26.793Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/scouten.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}},"created_at":"2023-09-22T00:12:30.000Z","updated_at":"2024-11-02T14:32:02.000Z","dependencies_parsed_at":"2024-08-29T23:47:33.695Z","dependency_job_id":null,"html_url":"https://github.com/scouten/async-generic","commit_stats":null,"previous_names":["scouten/async-generic"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scouten%2Fasync-generic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scouten%2Fasync-generic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scouten%2Fasync-generic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/scouten%2Fasync-generic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/scouten","download_url":"https://codeload.github.com/scouten/async-generic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227966467,"owners_count":17848598,"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":[],"created_at":"2024-12-03T17:38:51.088Z","updated_at":"2024-12-03T17:38:55.229Z","avatar_url":"https://github.com/scouten.png","language":"Rust","readme":"# async-generic\n\nWrite code that can be both async and synchronous without duplicating it.\n\n## Why solve this problem now?\n\nThis macro set is intended as an interim solution for the problem space that will eventually be covered by the Rust [Keyword Generic Initiative](https://blog.rust-lang.org/inside-rust/2022/07/27/keyword-generics.html).\n\nAs of this writing (September 2023), the official [status of that project](https://github.com/rust-lang/keyword-generics-initiative) is listed as still in the \"Experimental\" stage, so deployment in the language is still likely many months away if not longer.\n\nSo ... what do we do _now_ if we need async-generic code? We build our own, using proc macros. And that's exactly what this crate is.\n\nI'll happily mark this crate as deprecated when keyword generics land officially in the language. Until then, hopefully it solves some problems for you, too!\n\nIMPORTANT: This crate is quite simple, so I expect there will be few releases beyond the 1.0.0 release. If you encounter issues, pelase do file them here; I use this crate routinely in other projects and will be watching, even if I don't update it regularly.\n\n## User's guide\n\nThe `async_generic` crate introduces a single proc macro also named `async_generic` which can be applied as an attribute to any function (either inside a struct or not).\n\nThe macro outputs _two_ versions of the function, one synchronous and one that's async. The functions are identical to each other, except as follows:\n\n* When writing the async flavor of the function, the macro inserts the `async` modifier for you and renames the function (to avoid a name collision) by adding an `_async` suffix to the existing function name.\n* The attribute macro _may_ contain an `async_signature` argument. If that exists, the async function's argument parameters are replaced. (See example below.)\n* You can write `if _sync` or `if _async` blocks inside this block. The contents of these blocks will only appear in the corresponding sync or async flavors of the functions. You _may_ specify an `else` clause, which will only appear in the opposite flavor of the function. You may not combine `_sync` or `_async` with any other expression. (These aren't _really_ variables in the function scope, and they will cause \"undefined identifier\" errors if you try that.)\n\nA simple example:\n\n```rust\nuse async_generic::async_generic;\n\n#[async_generic]\nfn do_stuff() -\u003e String {\n    // Also: async fn do_stuff_async() -\u003e String {...}\n    if _async {\n        my_async_stuff().await\n    } else {\n        \"not async\".to_owned()\n    }\n}\n\nasync fn my_async_stuff() -\u003e String {\n    \"async\".to_owned()\n}\n\n#[async_std::main]\nasync fn main() {\n    println!(\"sync =\u003e {}\", do_stuff());\n    println!(\"async =\u003e {}\", do_stuff_async().await);\n}\n```\n\nAn example with different function arguments in the sync and async flavors:\n\n```rust\nuse async_generic::async_generic;\n\n#[async_generic(async_signature(thing: \u0026AsyncThing))]\nfn do_stuff(thing: \u0026SyncThing) -\u003e String {\n    // Also: async fn do_stuff_async(thing: \u0026AsyncThing) -\u003e String {...}\n    if _async {\n        thing.do_stuff().await\n    } else {\n        thing.do_stuff()\n    }\n}\n\nstruct SyncThing {}\n\nimpl SyncThing {\n    fn do_stuff(\u0026self) -\u003e String {\n        \"sync\".to_owned()\n    }\n}\n\nstruct AsyncThing {}\n\nimpl AsyncThing {\n    async fn do_stuff(\u0026self) -\u003e String {\n        \"async\".to_owned()\n    }\n}\n\n#[async_std::main]\nasync fn main() {\n    let st = SyncThing {};\n    let at = AsyncThing {};\n\n    println!(\"sync =\u003e {}\", do_stuff(\u0026st));\n    println!(\"async =\u003e {}\", do_stuff_async(\u0026at).await);\n}\n```\n\n## Why not use `maybe-async`?\n\nThis crate is loosely derived from the excellent work of the [`maybe-async`](https://crates.io/crates/maybe-async) crate, but is intended to solve a subtly different problem.\n\nUse `maybe-async` when you know at compile-time whether each crate in your dependency tree will be used in an async or synchronous fashion. In that model, you can't have both at once.\n\nUse `async-generic` when you wish to have both async and synchronous versions of an API at the same time and want to reuse most of the implementation.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscouten%2Fasync-generic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscouten%2Fasync-generic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscouten%2Fasync-generic/lists"}