{"id":15994811,"url":"https://github.com/jamesmunns/cassette","last_synced_at":"2025-10-14T13:09:05.992Z","repository":{"id":48499529,"uuid":"359224789","full_name":"jamesmunns/cassette","owner":"jamesmunns","description":"A simple, single-future, non-blocking executor intended for building state machines. Designed to be no-std and embedded friendly.","archived":false,"fork":false,"pushed_at":"2024-04-13T23:48:29.000Z","size":44,"stargazers_count":86,"open_issues_count":1,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-10-11T14:13:11.312Z","etag":null,"topics":["async","embedded","no-std","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/cassette","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/jamesmunns.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":"2021-04-18T18:38:05.000Z","updated_at":"2025-10-02T14:58:24.000Z","dependencies_parsed_at":"2024-01-09T17:00:25.067Z","dependency_job_id":"f5ccf225-dbcb-4635-b9f6-a75bf8451bf2","html_url":"https://github.com/jamesmunns/cassette","commit_stats":{"total_commits":22,"total_committers":2,"mean_commits":11.0,"dds":"0.045454545454545414","last_synced_commit":"d59a8f2cddd7a0443022fba25bbe62e2768602ac"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/jamesmunns/cassette","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesmunns%2Fcassette","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesmunns%2Fcassette/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesmunns%2Fcassette/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesmunns%2Fcassette/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesmunns","download_url":"https://codeload.github.com/jamesmunns/cassette/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesmunns%2Fcassette/sbom","scorecard":{"id":504060,"data":{"date":"2025-08-11","repo":{"name":"github.com/jamesmunns/cassette","commit":"9ffb1d472d466683a27da9d25b783c86a6e5bad3"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Code-Review","score":1,"reason":"Found 3/22 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:59: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:62: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:77: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:80: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:96: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:98: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:105: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:108: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:123: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:126: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/jamesmunns/cassette/ci.yml/main?enable=pin","Info:   0 out of   7 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   7 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE-APACHE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE-APACHE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 14 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-19T22:50:13.607Z","repository_id":48499529,"created_at":"2025-08-19T22:50:13.607Z","updated_at":"2025-08-19T22:50:13.607Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279014029,"owners_count":26085346,"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-10-13T02:00:06.723Z","response_time":61,"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":["async","embedded","no-std","rust"],"created_at":"2024-10-08T07:10:21.578Z","updated_at":"2025-10-14T13:09:05.974Z","avatar_url":"https://github.com/jamesmunns.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cassette\n\nA simple, single-future, non-blocking executor intended for building state machines. Designed to be no-std and embedded friendly.\n\nThis executor TOTALLY IGNORES wakers and context, meaning that all async functions should expect to be polled repeatedly until completion.\n\n## Inspiration\n\nSo, I'm really not good at async, but I like the idea of being able to use the ability to yield or await on tasks that will require some time to complete.\n\nThe idea here is that you would write one, top level `async` function that would either eventually resolve to some value, or that will run forever (to act as a state machine).\n\n## How it works\n\n1. You write some async functions\n2. You call the \"top level\" async function\n3. You poll on it until it resolves (or forever)\n\nNote: This demo is available in the [`demo/` folder](./demo) of this repo.\n\n### Step 1 - You write some async functions\n\nHere's the \"context\" of our state machine, describing a couple of high level behaviors, as well as individual substeps.\n\n```rust\nstruct Demo {\n    lol: u32,\n}\n\nimpl Demo {\n    async fn entry(\u0026mut self) {\n        for _ in 0..10 {\n            self.entry_1().await;\n            self.entry_2().await;\n        }\n    }\n\n    async fn entry_1(\u0026mut self) {\n        self.start_at_zero().await;\n        self.add_one_until_ten().await;\n        self.sub_one_until_zero().await;\n    }\n\n    async fn entry_2(\u0026mut self) {\n        self.start_at_five().await;\n        self.sub_one_until_zero().await;\n        self.add_one_until_ten().await;\n    }\n\n    async fn start_at_zero(\u0026mut self) {\n        self.lol = 0;\n    }\n\n    async fn start_at_five(\u0026mut self) {\n        self.lol = 5;\n    }\n\n    async fn add_one_until_ten(\u0026mut self) {\n        loop {\n            delay(self).await; // simulate fake delays/not ready state\n            self.lol += 1;\n            if self.lol \u003e= 10 {\n                return;\n            }\n        }\n    }\n\n    async fn sub_one_until_zero(\u0026mut self) {\n        loop {\n            delay(self).await; // simulate fake delays/not ready state\n            self.lol -= 1;\n            if self.lol == 0 {\n                return;\n            }\n        }\n    }\n}\n```\n\nWe can also make simple little futures for code that needs to be polled until ready:\n\n```rust\nstatic FAKE: AtomicU32 = AtomicU32::new(0);\nstruct CountFuture;\nimpl Future for CountFuture {\n    type Output = ();\n    fn poll(self: Pin\u003c\u0026mut Self\u003e, cx: \u0026mut Context\u003c'_\u003e) -\u003e Poll\u003cSelf::Output\u003e {\n        let x = FAKE.fetch_add(1, Ordering::SeqCst);\n        print!(\"{}, \", x);\n        if (x % 5) == 0 {\n            Poll::Ready(())\n        } else {\n            cx.waker().wake_by_ref();\n            Poll::Pending\n        }\n    }\n}\n\nasync fn delay(ctxt: \u0026mut Demo) {\n    println!(\"delay says lol: {}\", ctxt.lol);\n    let x = CountFuture;\n    x.await;\n    println!(\"and delay!\");\n}\n```\n\n### Step 2 - You call the \"top level\" async function\n\n```rust\nfn main() {\n    // Make a new struct\n    let mut demo = Demo { lol: 100 };\n\n    // Call the entry point future, and pin it\n    let x = core::pin::pin!(demo.entry());\n\n    // Give the pinned future to Cassette\n    // for execution\n    let mut cm = Cassette::new(x);\n\n    /* ... */\n}\n```\n\n### Step 3 - You poll on it until it resolves (or forever)\n\n```rust\nfn main() {\n    /* ... */\n\n    loop {\n        if let Some(x) = cm.poll_on() {\n            println!(\"Done!: `{:?}`\", x);\n            break;\n        }\n    }\n}\n```\n\n## A larger demo\n\nIf you'd like to see a larger demo, I used Cassette to implement an I2C peripheral bootloader state machine for a `thumbv6m` target. You can check out [that PR](https://github.com/sprocket-board/sprocket-boot/pull/1) for more context.\n\n## License\n\nThis crate is licensed under the [MIT](./LICENSE-MIT) and [Apache 2.0](./LICENSE-APACHE) licenses.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesmunns%2Fcassette","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesmunns%2Fcassette","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesmunns%2Fcassette/lists"}