{"id":20408912,"url":"https://github.com/freedomlayer/wait_spawner","last_synced_at":"2026-04-22T05:34:20.130Z","repository":{"id":87201036,"uuid":"174357509","full_name":"freedomlayer/wait_spawner","owner":"freedomlayer","description":"A spawner proxy for rust futures","archived":false,"fork":false,"pushed_at":"2019-03-07T15:18:54.000Z","size":13,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-05T02:41:38.993Z","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/freedomlayer.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2019-03-07T14:17:27.000Z","updated_at":"2019-03-07T15:18:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"584cd279-20a5-4f00-b6c5-35d939d28996","html_url":"https://github.com/freedomlayer/wait_spawner","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/freedomlayer/wait_spawner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freedomlayer%2Fwait_spawner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freedomlayer%2Fwait_spawner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freedomlayer%2Fwait_spawner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freedomlayer%2Fwait_spawner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/freedomlayer","download_url":"https://codeload.github.com/freedomlayer/wait_spawner/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/freedomlayer%2Fwait_spawner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32122762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-22T00:31:26.853Z","status":"online","status_checked_at":"2026-04-22T02:00:05.693Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-11-15T05:38:08.223Z","updated_at":"2026-04-22T05:34:20.102Z","avatar_url":"https://github.com/freedomlayer.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# WaitSpawner\n\nWaitSpawner allows to drive a Rust Futures executor until no more progress is\npossible. \n\nPossible uses:\n\n- Writing tests for your asynchronous code.\n- Solving deadlocks in your asynchronous code.\n\n\n## Example\n\n```rust\n#![feature(futures_api, async_await, await_macro, arbitrary_self_types)]\n#![feature(generators)]\n\nextern crate wait_spawner;\n\nuse std::sync::{Arc, Mutex};\nuse futures::channel::mpsc;\nuse futures::task::SpawnExt;\nuse futures::{StreamExt, SinkExt};\nuse futures::executor::ThreadPool;\n\nuse wait_spawner::WaitSpawner;\n\nfn main() {\n    let mut thread_pool = ThreadPool::new().unwrap();\n\n    let mut wspawner = WaitSpawner::new(thread_pool.clone());\n    let waiter = wspawner.wait();\n\n    let (mut a_sender, mut b_receiver) = mpsc::channel::\u003cu32\u003e(0);\n    let (mut b_sender, mut a_receiver) = mpsc::channel::\u003cu32\u003e(0);\n\n    // We spawn two futures that have a conversation.\n    // Spawn first future:\n    wspawner.spawn(async move {\n        await!(a_sender.send(0)).unwrap();\n        assert_eq!(await!(a_receiver.next()).unwrap(), 1);\n        await!(a_sender.send(2)).unwrap();\n    }).unwrap();\n\n    // A shared result value, used to make sure that the second future\n    // has finished\n    let arc_mutex_res = Arc::new(Mutex::new(false));\n    let c_arc_mutex_res = Arc::clone(\u0026arc_mutex_res);\n\n    // Spawn second future:\n    wspawner.spawn(async move {\n        assert_eq!(await!(b_receiver.next()).unwrap(), 0);\n        await!(b_sender.send(1)).unwrap();\n        assert_eq!(await!(b_receiver.next()).unwrap(), 2);\n        let mut res_guard = c_arc_mutex_res.lock().unwrap();\n        *res_guard = true;\n    }).unwrap();\n\n    // Keep running until no more progress is possible\n    thread_pool.run(waiter);\n\n    // Make sure that the second future has finished:\n    let res_guard = arc_mutex_res.lock().unwrap();\n    assert!(*res_guard);\n}\n```\n\n## How does WaitSpawner work?\n\nWaitSpawner serves as a proxy over your spawner.\nIt intercepts the following events:\n\n- Spawning a future.\n- The beginning and end of a `poll()` invocation over any future that was spawned through the WaitSpawner proxy.\n- A call to `wake()` on any `Waker`\n\nWaitSpawner maintains:\n- A set of all futures in progress.\n- The current amount of in progress `poll()` invocations.\n\nSpawning a future adds the future to the set.\nThe beginning of a `poll()` invocation removes a future from the set. A call to\n`wake()` on the future's `Waker` will put the future back on the set.\n\nOn any ending of a `poll()` invocation we check if the two following conditions are satisfied:\n- The set of futures in progress is empty\n- There are no more polls in progress.\n\nif the two conditions are met, WaitSpawner notifies that no more progress can\nbe made.\n\n\n## Information collection\n\nIf you choose to, WaitSpawner can collect information about the spawn sites for\nall the spawned futures and print it to the screen. This can be useful to debug\nyour asynchronous code.\n\nTo activate information collection, construct WaitSpawn as follows:\n\n```rust\nlet mut wspawner = WaitSpawner::new(thread_pool.clone())\n                                    .collect_info();\n\n```\n\nThis is example of the produced output:\n\n```\n---------[poll_end]----------\nonging_polls = 0\n\n---------[poll_end]----------\nonging_polls = 0\nid = 0\ncaller_info = Some(CallerInfo { name: \"wait_spawner::wait_spawner::tests::test_two_futures::h55a9ee6c5603873e\", filename: \"src/wait_spawner.rs\", lineno: 438 })\n\n---------[poll_end]----------\nonging_polls = 0\nid = 1\ncaller_info = Some(CallerInfo { name: \"wait_spawner::wait_spawner::tests::test_two_futures::h55a9ee6c5603873e\", filename: \"src/wait_spawner.rs\", lineno: 445 })\n\n---------[poll_end]----------\nonging_polls = 0\n```\n\nNote that a print occurs every time a `poll()` invocation ends.\nEvery print contains the following information:\n\n- The amount of ongoing `poll()` invocations.\n- A list of all futures in progress. For each future:\n    - A unique id.\n    - Information about the spawn site. (The code that called `spawn()` or `spawn_with_handle()`)\n\n\n## License\n\nThis project is licensed under either of\n\n * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or\n   https://www.apache.org/licenses/LICENSE-2.0)\n * MIT license ([LICENSE-MIT](LICENSE-MIT) or\n   https://opensource.org/licenses/MIT)\n\nat your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreedomlayer%2Fwait_spawner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffreedomlayer%2Fwait_spawner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffreedomlayer%2Fwait_spawner/lists"}