{"id":30178357,"url":"https://github.com/sysgrok/edge-executor","last_synced_at":"2025-12-12T14:21:15.154Z","repository":{"id":50599033,"uuid":"519567664","full_name":"sysgrok/edge-executor","owner":"sysgrok","description":"A minimal async executor suitable for embedded environments","archived":false,"fork":false,"pushed_at":"2023-11-09T12:50:56.000Z","size":85,"stargazers_count":39,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-31T19:39:45.494Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/sysgrok.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":"2022-07-30T16:32:50.000Z","updated_at":"2025-07-31T11:46:29.000Z","dependencies_parsed_at":"2023-01-31T19:16:03.397Z","dependency_job_id":"5c510f6e-5441-4154-9e60-253b8475c61d","html_url":"https://github.com/sysgrok/edge-executor","commit_stats":{"total_commits":80,"total_committers":1,"mean_commits":80.0,"dds":0.0,"last_synced_commit":"aaa6e47cfefe68dd06cd341b6cc4d229377dc776"},"previous_names":["sysgrok/edge-executor"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/sysgrok/edge-executor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysgrok%2Fedge-executor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysgrok%2Fedge-executor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysgrok%2Fedge-executor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysgrok%2Fedge-executor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sysgrok","download_url":"https://codeload.github.com/sysgrok/edge-executor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sysgrok%2Fedge-executor/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270005591,"owners_count":24510939,"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","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"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":"2025-08-12T05:20:36.474Z","updated_at":"2025-12-12T14:21:10.099Z","avatar_url":"https://github.com/sysgrok.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# edge-executor\n\n[![CI](https://github.com/ivmarkov/edge-executor/actions/workflows/ci.yml/badge.svg)](https://github.com/ivmarkov/edge-executor/actions/workflows/ci.yml)\n![crates.io](https://img.shields.io/crates/v/edge-executor.svg)\n[![Documentation](https://docs.rs/edge-executor/badge.svg)](https://docs.rs/edge-executor)\n\nThis crate ships a minimal async executor suitable for microcontrollers and embedded systems in general.\n\nA `no_std` drop-in replacement for [smol](https://github.com/smol-rs/smol)'s [async-executor](https://github.com/smol-rs/async-executor), with the implementation being a thin wrapper around [smol](https://github.com/smol-rs/smol)'s [async-task](https://github.com/smol-rs/async-task) as well.\n\n## Examples\n\n```rust\n// ESP-IDF example, local execution, local borrows.\n// With STD enabled, you can also just use `edge_executor::block_on` \n// instead of `esp_idf_svc::hal::task::block_on`.\n\nuse edge_executor::LocalExecutor;\nuse esp_idf_svc::hal::task::block_on;\n\nfn main() {\n    let local_ex: LocalExecutor = Default::default();\n\n    // Borrowed by `\u0026mut` inside the future spawned on the executor\n    let mut data = 3;\n\n    let data = \u0026mut data;\n\n    let task = local_ex.spawn(async move {\n        *data += 1;\n\n        *data\n    });\n\n    let res = block_on(local_ex.run(async { task.await * 2 }));\n\n    assert_eq!(res, 8);\n}\n```\n\n```rust\n// STD example, work-stealing execution.\n\nuse async_channel::unbounded;\nuse easy_parallel::Parallel;\n\nuse edge_executor::{Executor, block_on};\n\nfn main() {\n    let ex: Executor = Default::default();\n    let (signal, shutdown) = unbounded::\u003c()\u003e();\n\n    Parallel::new()\n        // Run four executor threads.\n        .each(0..4, |_| block_on(ex.run(shutdown.recv())))\n        // Run the main future on the current thread.\n        .finish(|| block_on(async {\n            println!(\"Hello world!\");\n            drop(signal);\n        }));\n}\n```\n\n```rust\n// WASM example.\n\nuse log::{info, Level};\n\nuse edge_executor::LocalExecutor;\n\nuse static_cell::StaticCell;\nuse wasm_bindgen_futures::spawn_local;\n\nuse gloo_timers::future::TimeoutFuture;\n\nstatic LOCAL_EX: StaticCell\u003cLocalExecutor\u003e = StaticCell::new();\n\nfn main() {\n    console_log::init_with_level(Level::Info).unwrap();\n\n    // Local executor (futures can be `!Send`) yet `'static`\n    let local_ex = \u0026*LOCAL_EX.init(Default::default());\n\n    local_ex\n        .spawn(async {\n            loop {\n                info!(\"Tick\");\n                TimeoutFuture::new(1000).await;\n            }\n        })\n        .detach();\n\n    spawn_local(local_ex.run(core::future::pending::\u003c()\u003e()));\n}\n```\n\n## Highlights\n\n- `no_std` (but does need `alloc`):\n  - The executor uses allocations in a controlled way: only when a new task is being spawn, as well as during the construction of the executor itself;\n  - For a `no_std` *and* \"no_alloc\" executor, look at [embassy-executor](https://github.com/embassy-rs/embassy/tree/main/embassy-executor), which statically pre-allocates all tasks.\n- Works on targets which have no `core::sync::atomic` support, thanks to [portable-atomic](https://github.com/taiki-e/portable-atomic);\n- Does not assume an RTOS and can run completely bare-metal too;\n- Lockless, atomic-based, bounded task queue by default, which works well for waking the executor directly from an ISR on e.g. FreeRTOS or ESP-IDF (unbounded also an option with feature `unbounded`, yet that might mean potential allocations in an ISR context, which should be avoided).\n\n### Great features carried over from [async-executor](https://github.com/smol-rs/async-executor):\n\n- Stack borrows: futures spawned on the executor need to live only as long as the executor itself. No `F: Future + 'static` constraints;\n- Completely portable and async. `Executor::run` simply returns a `Future`. Polling this future runs the executor, i.e. `block_on(executor.run(core::future:pending::\u003c()\u003e()))`;\n- `const new` constructor function.\n\n---\n**NOTE**:\nTo compile on `no_std` targets that do **not** have atomics in Rust `core` (i.e. `riscv32imc-unknown-none-elf` and similar single-core MCUs),\nenable features `portable-atomic` and `critical-section`. I.e.:\n```sh\ncargo build --features portable-atomic,critical-section --no-default-features --target \u003cyour-target\u003e\n```\n---\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsysgrok%2Fedge-executor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsysgrok%2Fedge-executor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsysgrok%2Fedge-executor/lists"}