{"id":27273552,"url":"https://github.com/adel-mamin/amast","last_synced_at":"2026-04-02T16:24:18.172Z","repository":{"id":255513044,"uuid":"852315568","full_name":"adel-mamin/amast","owner":"adel-mamin","description":"A Minimalist Asynchronous Toolkit (AMAST) is a small and efficient C99 library that helps manage complex, event-driven programs. It combines the Actor model with hierarchical state machines to make building real-time systems easier.","archived":false,"fork":false,"pushed_at":"2026-03-28T06:28:12.000Z","size":2223,"stargazers_count":25,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-03-28T11:38:12.580Z","etag":null,"topics":["active-object","async","async-await","asynchronous-programming","c99","embedded","embedded-systems","event-driven","finite-state-machine","firmware","fsm","fsm-library","hierarchical-state-machine","hsm","libuv","real-time-event-framework","rtef","state-machine","statechart"],"latest_commit_sha":null,"homepage":"https://amast.readthedocs.io/","language":"C","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adel-mamin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/contributing.rst","funding":".github/FUNDING.yml","license":"LICENSE.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["adel-mamin"]}},"created_at":"2024-09-04T15:43:30.000Z","updated_at":"2026-03-28T06:28:16.000Z","dependencies_parsed_at":"2025-04-11T14:58:36.709Z","dependency_job_id":"ebd39f2e-adb4-4685-9719-e46493b22d33","html_url":"https://github.com/adel-mamin/amast","commit_stats":null,"previous_names":["adel-mamin/amast"],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/adel-mamin/amast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adel-mamin%2Famast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adel-mamin%2Famast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adel-mamin%2Famast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adel-mamin%2Famast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adel-mamin","download_url":"https://codeload.github.com/adel-mamin/amast/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adel-mamin%2Famast/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31309834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["active-object","async","async-await","asynchronous-programming","c99","embedded","embedded-systems","event-driven","finite-state-machine","firmware","fsm","fsm-library","hierarchical-state-machine","hsm","libuv","real-time-event-framework","rtef","state-machine","statechart"],"created_at":"2025-04-11T14:58:18.504Z","updated_at":"2026-04-02T16:24:18.163Z","avatar_url":"https://github.com/adel-mamin.png","language":"C","funding_links":["https://github.com/sponsors/adel-mamin"],"categories":[],"sub_categories":[],"readme":"[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Version](https://img.shields.io/badge/version-0.15.1-blue)](https://github.com/adel-mamin/amast/releases)\n[![Sphynx](https://img.shields.io/badge/Docs-Sphinx-gainsboro)](https://amast.readthedocs.io/)\n![Visitors](https://visitor-badge.laobi.icu/badge?page_id=adel-mamin.amast)\n\n# Amast\n\n## Introduction\n\u003ca name=\"introduction\"\u003e\u003c/a\u003e\n\nAmast is a minimalist asynchronous toolkit to help developing projects with asynchronous interactions and state machines.\nWritten in C99.\n\n## What is it useful for?\n\nHere are several use cases in increasing level of complexity.\n\n### Finite state machine (FSM)\n\nThe FSM has two states:\n\n```mermaid\nstateDiagram-v2\n    direction LR\n\n    [*] --\u003e state_a\n\n    state_a --\u003e state_b : B\n    state_b --\u003e state_a : A\n```\n\nHere is the full implementation of the FSM:\n\n```C\n#include \"amast_config.h\"\n#include \"amast.h\"\n\n#define EVT_A AM_EVT_USER\n#define EVT_B (AM_EVT_USER + 1)\n\nstruct app {\n    /*\n     * Must be the first member of the structure.\n     * See https://amast.readthedocs.io/fsm.html#fsm-coding-rules\n     */\n    struct am_fsm fsm;\n    /* app data */\n} app;\n\nstatic enum am_rc state_b(struct app *me, const struct am_event *event);\n\nstatic enum am_rc state_a(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"state_a entry\\n\");\n        return AM_FSM_HANDLED();\n\n    case AM_EVT_EXIT:\n        am_printf(\"state_a exit\\n\");\n        return AM_FSM_HANDLED();\n\n    case EVT_B:\n        return AM_FSM_TRAN(state_b);\n    }\n    return AM_FSM_HANDLED();\n}\n\nstatic enum am_rc state_b(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"state_b entry\\n\");\n        return AM_FSM_HANDLED();\n\n    case AM_EVT_EXIT:\n        am_printf(\"state_b exit\\n\");\n        return AM_FSM_HANDLED();\n\n    case EVT_A:\n        return AM_FSM_TRAN(state_a);\n    }\n    return AM_FSM_HANDLED();\n}\n\nstatic enum am_rc init(struct app *me, const struct am_event *event) {\n    return AM_FSM_TRAN(state_a);\n}\n\nint main(void) {\n    am_fsm_ctor(\u0026app.fsm, AM_FSM_STATE_CTOR(init));\n    am_fsm_init(\u0026app.fsm, /*init_event=*/NULL);\n    am_fsm_dispatch(\u0026app.fsm, \u0026(struct am_event){.id = EVT_B});\n    am_fsm_dispatch(\u0026app.fsm, \u0026(struct am_event){.id = EVT_A});\n    return 0;\n}\n```\n\nThe console output:\n\n```\nstate_a entry\nstate_a exit\nstate_b entry\nstate_b exit\nstate_a entry\n```\n\nThe FSM API can be found [here](https://amast.readthedocs.io/api.html#fsm).\nThe FSM documenation is [here](https://amast.readthedocs.io/fsm.html).\n\nThe compiled binary on x86 is about 2.4kB of memory (gcc, `-Os`, `-flto`).\n\n### Hierarchical state machine (HSM)\n\nThe HSM has two sub-states and one superstate.\n\nIt demonstrates:\n\n1. creating of hierarchy of states\n2. behavioral inheritance by handling the event C in superstate\n\n```mermaid\nstateDiagram-v2\n    direction LR\n\n    [*] --\u003e superstate : init\n\n    state superstate {\n        [*] --\u003e substate_a\n\n        substate_a --\u003e substate_b : B\n        substate_b --\u003e substate_a : A\n    }\n\n    superstate --\u003e substate_b : C\n```\n\nHere is the full implementation of the HSM:\n\n```C\n#include \u003cstdio.h\u003e\n\n#include \"amast_config.h\"\n#include \"amast.h\"\n\nenum { APP_EVT_A = AM_EVT_USER, APP_EVT_B, APP_EVT_C };\n\nstruct app {\n    /*\n     * Must be the first member of the structure.\n     * See https://amast.readthedocs.io/hsm.html#hsm-coding-rules\n     */\n    struct am_hsm hsm;\n    /* app data */\n} app;\n\nstatic enum am_rc substate_a(struct app *me, const struct am_event *event);\nstatic enum am_rc substate_b(struct app *me, const struct am_event *event);\n\nstatic enum am_rc superstate(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"superstate entry\\n\");\n        return AM_HSM_HANDLED();\n\n    case AM_EVT_EXIT:\n        am_printf(\"superstate exit\\n\");\n        return AM_HSM_HANDLED();\n\n    case AM_EVT_INIT:\n        return AM_HSM_TRAN(substate_a);\n\n    case APP_EVT_C:\n        return AM_HSM_TRAN(substate_b);\n    }\n    return AM_HSM_SUPER(am_hsm_top);\n}\n\nstatic enum am_rc substate_a(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"substate_a entry\\n\");\n        return AM_HSM_HANDLED();\n\n    case AM_EVT_EXIT:\n        am_printf(\"substate_a exit\\n\");\n        return AM_HSM_HANDLED();\n\n    case APP_EVT_B:\n        return AM_HSM_TRAN(substate_b);\n    }\n    return AM_HSM_SUPER(superstate);\n}\n\nstatic enum am_rc substate_b(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"substate_b entry\\n\");\n        return AM_HSM_HANDLED();\n\n    case AM_EVT_EXIT:\n        am_printf(\"substate_b exit\\n\");\n        return AM_HSM_HANDLED();\n\n    case APP_EVT_A:\n        return AM_HSM_TRAN(substate_a);\n    }\n    return AM_HSM_SUPER(superstate);\n}\n\nstatic enum am_rc init(struct app *me, const struct am_event *event) {\n    return AM_HSM_TRAN(superstate);\n}\n\nint main(void) {\n    am_hsm_ctor(\u0026app.hsm, AM_HSM_STATE_CTOR(init));\n    am_hsm_init(\u0026app.hsm, /*init_event=*/NULL);\n    am_hsm_dispatch(\u0026app.hsm, \u0026(struct am_event){.id = APP_EVT_B});\n    am_hsm_dispatch(\u0026app.hsm, \u0026(struct am_event){.id = APP_EVT_A});\n    am_hsm_dispatch(\u0026app.hsm, \u0026(struct am_event){.id = APP_EVT_C});\n    return 0;\n}\n```\n\nThe console output:\n\n```\nsuperstate entry\nsubstate_a entry\nsubstate_a exit\nsubstate_b entry\nsubstate_b exit\nsubstate_a entry\nsubstate_a exit\nsubstate_b entry\n```\n\nThe HSM API can be found [here](https://amast.readthedocs.io/api.html#hsm).\nThe HSM documenation is [here](https://amast.readthedocs.io/hsm.html).\n\nThe compiled binary on x86 is about 4.0kB of memory (gcc, `-Os`, `-flto`).\n\n### Active Object\n\nHere is a full implementation of one active object with two states.\n\nIt demonstrates:\n\n1. creating the active object\n2. creating and maintaining a timer\n3. event publishing\n4. creating regular tasks, for blocking calls like\n   sleep and waiting for user input\n\n```C\n#include \u003cstdio.h\u003e\n#include \u003cstddef.h\u003e\n#include \u003cstring.h\u003e\n\n#include \"amast_config.h\"\n#include \"amast.h\"\n\nenum {\n    APP_EVT_SWITCH_MODE = AM_EVT_USER,\n    APP_EVT_PUB_MAX,\n    APP_EVT_TIMER,\n};\n\nstruct app {\n    /*\n     * Must be the first member of the structure.\n     * See https://amast.readthedocs.io/hsm.html#hsm-coding-rules for details\n     */\n    struct am_hsm hsm;\n    struct am_ao ao;\n    struct am_timer *timer;\n    struct am_timer_event timeout;\n    int ticks;\n};\n\n/* event publish/subscribe memory */\nstatic struct am_ao_subscribe_list m_pubsub_list[APP_EVT_PUB_MAX];\n\n/* active object incoming events queue */\nstatic const struct am_event *m_queue[2];\n\nstatic enum am_rc app_state_a(struct app *me, const struct am_event *event);\nstatic enum am_rc app_state_b(struct app *me, const struct am_event *event);\n\nstatic enum am_rc app_state_a(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"state A\\n\");\n        return AM_HSM_HANDLED();\n\n    case APP_EVT_SWITCH_MODE:\n        return AM_HSM_TRAN(app_state_b);\n    }\n    return AM_HSM_SUPER(am_hsm_top);\n}\n\nstatic enum am_rc app_state_b(struct app *me, const struct am_event *event) {\n    switch (event-\u003eid) {\n    case AM_EVT_ENTRY:\n        am_printf(\"state B\\n\");\n        am_timer_arm(me-\u003etimer, \u0026me-\u003etimeout.event, me-\u003eticks, /*interval=*/0);\n        return AM_HSM_HANDLED();\n\n    case AM_EVT_EXIT:\n        am_timer_disarm(me-\u003etimer, \u0026me-\u003etimeout.event);\n        return AM_HSM_HANDLED();\n\n    case APP_EVT_SWITCH_MODE:\n        return AM_HSM_TRAN(app_state_a);\n\n    case APP_EVT_TIMER:\n        am_printf(\"timer\\n\");\n        am_timer_arm(me-\u003etimer, \u0026me-\u003etimeout.event, me-\u003eticks, /*interval=*/0);\n        return AM_HSM_HANDLED();\n    }\n    return AM_HSM_SUPER(am_hsm_top);\n}\n\nstatic enum am_rc app_init(struct app *me, const struct am_event *event) {\n    am_ao_subscribe(\u0026me-\u003eao, APP_EVT_SWITCH_MODE);\n    return AM_HSM_TRAN(app_state_a);\n}\n\nstatic void app_ctor(struct app *me, struct am_timer *timer) {\n    memset(me, 0, sizeof(*me));\n    am_ao_ctor(\u0026me-\u003eao, (am_ao_fn)am_hsm_init, (am_ao_fn)am_hsm_dispatch, me);\n    am_hsm_ctor(\u0026me-\u003ehsm, AM_HSM_STATE_CTOR(app_init));\n    me-\u003etimer = timer;\n    me-\u003etimout = am_timer_event_ctor_x(APP_EVT_TIMER, \u0026me-\u003eao);\n    me-\u003eticks = am_time_get_tick_from_ms(AM_PAL_TICK_DOMAIN_DEFAULT, 1000);\n}\n\nstatic void ticker_task(void *param) {\n    struct am_timer *timer = param;\n\n    am_task_startup_gate_wait();\n\n    const int domain = AM_TICK_DOMAIN_DEFAULT;\n    const uint32_t ticks_per_ms = am_time_get_tick_from_ms(domain, 1);\n    uint32_t now_ticks = am_time_get_tick(domain);\n    while (am_ao_get_cnt() \u003e 0) {\n        am_sleep_till_ticks(domain, now_ticks + ticks_per_ms);\n        now_ticks += ticks_per_ms;\n        am_timer_tick(timer, domain);\n\n        am_timer_tick_iterator_init(timer);\n        struct am_timer_event* fired = NULL;\n        while ((fired = am_timer_tick_iterator_next(timer)) != NULL) {\n            void *owner = AM_CAST(struct am_timer_event_x *, fired)-\u003ectx;\n            if (owner) {\n                am_ao_post_fifo(owner, \u0026fired-\u003eevent);\n            } else {\n                am_ao_publish(\u0026fired-\u003eevent);\n            }\n        }\n    }\n}\n\nstatic void input_task(void *param) {\n    am_task_startup_gate_wait();\n\n    int ch;\n    while ((ch = getc(stdin)) != EOF) {\n        if ('\\n' == ch) {\n            static struct am_event event = {.id = APP_EVT_SWITCH_MODE};\n            am_ao_publish(\u0026event);\n        }\n    }\n}\n\nint main(void) {\n    am_pal_ctor(/*arg=*/NULL);\n\n    struct am_timer timer;\n    am_timer_ctor(\u0026timer);\n\n    am_ao_state_ctor(/*cfg=*/NULL);\n    am_event_pool_add(\n        m_event_pool,\n        sizeof(m_event_pool),\n        sizeof(m_event_pool[0]),\n        AM_ALIGNOF(am_event_t)\n    );\n    am_ao_init_subscribe_list(m_pubsub_list, AM_COUNTOF(m_pubsub_list));\n\n    struct app m;\n    app_ctor(\u0026m, \u0026timer);\n\n    am_ao_start(\n        \u0026m.ao,\n        (struct am_ao_prio){.ao = AM_AO_PRIO_MAX, .task = AM_AO_PRIO_MAX},\n        /*queue=*/m_queue,\n        /*queue_size=*/AM_COUNTOF(m_queue),\n        /*stack=*/NULL,\n        /*stack_size=*/0,\n        /*name=*/\"app\",\n        /*init_event=*/NULL\n    );\n\n    /* ticker thread to feed timers */\n    am_task_create(\n        \"ticker\",\n        AM_AO_PRIO_MIN,\n        /*stack=*/NULL,\n        /*stack_size=*/0,\n        /*entry=*/ticker_task,\n        /*flags=*/0,\n        /*arg=*/\u0026timer\n    );\n\n    /* user input controlling thread */\n    am_task_create(\n        \"input\",\n        AM_AO_PRIO_MIN,\n        /*stack=*/NULL,\n        /*stack_size=*/0,\n        /*entry=*/input_task,\n        /*flags=*/0,\n        /*arg=*/\u0026m\n    );\n\n    while (am_ao_get_cnt() \u003e 0) {\n        am_ao_run_all();\n    }\n\n    am_ao_state_dtor();\n\n    am_pal_dtor();\n\n    return 0;\n}\n```\n\nThe AO API can be found [here](https://amast.readthedocs.io/api.html#ao).\nThe Event API can be found [here](https://amast.readthedocs.io/api.html#event).\nThe Timer API can be found [here](https://amast.readthedocs.io/api.html#timer).\n\nThe compiled binary on x86 is about 10.6kB of memory (gcc, `-Os`, `-flto`).\n\n## Architecture Diagram\n\n![Architecture Diagram](docs/amast-app-diagram.jpg)\n\n## What Is Inside\n\nLibrary name | Description\n-------------|------------\nao | active object (preemptive and cooperative) ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/ao/README.rst), [example](https://github.com/adel-mamin/amast/tree/main/apps/examples/dpp))\nasync | async/await ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/async/README.rst), [example](https://github.com/adel-mamin/amast/tree/main/apps/examples/async))\ndlist | doubly linked list\nevent | events ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/event/README.rst))\nfsm | finite state machine (FSM) ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/fsm/README.rst))\nhsm | hierarchical state machine (HSM) with sub-machines support ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/hsm/README.rst), [examples](https://github.com/adel-mamin/amast/tree/main/apps/examples/hsm))\nonesize | onesize memory allocator ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/onesize/README.rst))\nringbuf | ring buffer ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/ringbuf/README.rst), [example](https://github.com/adel-mamin/amast/tree/main/apps/examples/ringbuf))\nslist | singly linked list\ntimer | timers ([documentation](https://github.com/adel-mamin/amast/blob/main/libs/timer/README.rst))\n\n## How Big Are Compile Sizes\n\nSome x86-64 size figures to get an idea:\n\n\u003c!--\nGenerated by disabling `-ftrav`, address and undefined sanitizers.\nMeson build type is set to `minsize`.\nLTO is disabled.\n--\u003e\n\nLibrary name | Code size [kB] | Data size [kB]\n-------------|----------------|---------------\nao_cooperative | 3.61 | 0.57\nao_preemptive | 3.55 | 0.56\ndlist | 1.29 | 0.00\nevent | 4.00 | 0.23\nfsm | 0.88 | 0.00\nhsm | 2.66 | 0.01\nonesize | 1.43 | 0.00\nringbuf | 1.55 | 0.00\nslist | 1.21 | 0.00\ntimer | 1.03 | 0.08\n\n## How To Compile For Amast Development\n\u003ca name=\"how-to-compile\"\u003e\u003c/a\u003e\n\nOn Linux or WSL:\n\nInstall [pixi](https://pixi.sh/latest/#installation).\nRun `pixi run all`.\n\n## How To Use The Latest Amast Release\n\u003ca name=\"how-to-use\"\u003e\u003c/a\u003e\n\nInclude\n\n- `amast.h`\n- `amast_config.h`\n- `amast.c`\n- `amast_preemptive.c` or `amast_cooperative.c`\n\nfrom the latest release to your project.\n\nIf you want to use Amast features that require porting, then also add the following\nport to you project:\n\n- `amast_posix.c`\n- `amast_libuv.c`\n\nIf you want to run Amast unit tests, then also include `amast_test.h` and `amast_test.c`.\n\n`Makefile` is available for optional use. Run `make test` to run the unit tests.\n\n## Features, Bugs, etc.\n\nThe project uses \"Discussions\" instead of \"Issues\".\n\n\"Discussions\" tab has different discussion groups for \"Features\" and \"Bugs\".\n\nFor making sure issues are addressed, both me and the community can better evaluate which issues and features are high priority because they can be \"upvoted\".\n\n## How To Contribute\n\nIf you find the project useful, then please star it. It helps promoting it.\n\nIf you find any bugs, please report them.\n\n## License\n\u003ca name=\"license\"\u003e\u003c/a\u003e\n\nAmast is open-sourced software licensed under the [MIT license](LICENSE.md).\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=adel-mamin/amast\u0026type=Date)](https://star-history.com/#adel-mamin/amast\u0026Date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadel-mamin%2Famast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadel-mamin%2Famast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadel-mamin%2Famast/lists"}