{"id":18352362,"url":"https://github.com/limpix31/turbostate","last_synced_at":"2025-09-20T07:55:29.575Z","repository":{"id":221939808,"uuid":"755838300","full_name":"LIMPIX31/turbostate","owner":"LIMPIX31","description":"Finite State Machine builder written in Rust","archived":false,"fork":false,"pushed_at":"2024-03-20T17:29:56.000Z","size":50,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-12T00:47:15.720Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LIMPIX31.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2024-02-11T08:17:48.000Z","updated_at":"2024-05-25T10:16:40.000Z","dependencies_parsed_at":"2024-11-05T21:40:41.167Z","dependency_job_id":null,"html_url":"https://github.com/LIMPIX31/turbostate","commit_stats":null,"previous_names":["limpix31/turbostate"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LIMPIX31/turbostate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIMPIX31%2Fturbostate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIMPIX31%2Fturbostate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIMPIX31%2Fturbostate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIMPIX31%2Fturbostate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LIMPIX31","download_url":"https://codeload.github.com/LIMPIX31/turbostate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIMPIX31%2Fturbostate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276064334,"owners_count":25578999,"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-09-20T02:00:10.207Z","response_time":63,"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-05T21:35:44.759Z","updated_at":"2025-09-20T07:55:29.537Z","avatar_url":"https://github.com/LIMPIX31.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Turbostate\n\n###### I just needed a state machine, so I wrote this.\n\n## Build engine by example\n\n### 1. Add imports\n\n```rust\nuse turbostate::engine;\nuse turbostate::Engine;\n```\n\n### 2. Define possible states, events and errors\n\n* `State` - All possible states. There is only one state at a time\n* `Event` - The driving part of the machine. By sending events you can change the state.\n* `Error` - Point out anything that could go wrong here. If something bad happens, the error will be raised.\n\n```rust\n// Required derive: Clone\n// Recommended derive: Default\n#[derive(Debug, Clone, Default)]\npub enum State {\n\t// It is good practice to specify a initial state (#[default])\n\t#[default]\n\tDisabled,\n\tEnabled,\n\tBroken,\n}\n\n#[derive(Debug)]\npub enum Event {\n\t// This event will toggle the switch.\n\tToggle,\n\t// We can deliberately break the switch\n\tBreak,\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"The switch is broken\")]\nstruct BrokenSwitchError;\n\n// turbostate captures the required types by a fixed name\n// and there is no way to change this yet.\n// State and Event should always be named like this,\n// if this is not the case, as for example with an error,\n// you should create typealias.\ntype Error = BrokenSwitchError;\n```\n\n### 3. Build engine\n\n`Engine` works like a gearbox, you pull the lever(send an event) and change the state\n\n```rust\nuse Event::*;\n// Use all variants for cleaner code\nuse State::*;\n\n// You can share any data not depending on the state within the engine\n// All derives are optional\n#[derive(Debug, Default)]\nstruct SwitchEngine {\n\tclicks: u32\n}\n\n// Or #[engine(async)] for async branches\n#[engine]\nimpl SwitchEngine {\n\t// branch attribute accepts familiar match arm\n\t// This works like:\n\t// match (state, event) {\n\t//   (Disabled, Switch) =\u003e Transition(Enabled),\n\t//   ...\n\t// }\n\t// Note: The return type is not needed\n\t#[branch((Disabled, Toggle))]\n\tfn disabled_switch(\u0026mut self) {\n\t\tself.clicks += 1;\n\t\t// Transition to a new state\n\t\tEnabled\n\t}\n\n\t#[branch((Enabled, Toggle))]\n\tfn enabled_switch(\u0026mut self) {\n\t\tself.clicks += 1;\n\t\tDisabled\n\t}\n\n\t#[branch((_, Break))]\n\tfn any_break(\u0026self) {\n\t\tBroken\n\t}\n\n\t#[branch((Broken, _))]\n\tfn broken_any(\u0026self) {\n\t\tErr(BrokenSwitchError)\n\t}\n\n\t// Do nothing, e.g if you trying to enable the switch while it is already enabled\n\t#[branch((state, _))]\n\tfn rest(\u0026self, state: State) {\n\t\tstate\n\t}\n}\n```\n\n### 4. You can start the engine manually\n\n```rust\nfn main() -\u003e anyhow::Result\u003c()\u003e {\n\tlet mut engine = SwitchEngine::default();\n\tlet mut state = State::default();\n\n\tstate = engine.next(state, Event::Toggle)?;\n\tassert!(matches!(state, State::Enabled));\n\tstate = engine.next(state, Event::Toggle)?;\n\tstate = engine.next(state, Event::Toggle)?;\n\tstate = engine.next(state, Event::Break)?;\n\tassert!(matches!(state, State::Broken));\n\t// ERROR: The switch is broken!\n\tstate = engine.next(state, Event::Toggle)?;\n\n\tOk(())\n}\n```\n\n\u003e [!Note]\n\u003e `turbostate` leaves the implementation of the machine (i.e. what will advance the state) up to you.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flimpix31%2Fturbostate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flimpix31%2Fturbostate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flimpix31%2Fturbostate/lists"}