单状态机式 Promise 实现

单状态机式 Promise 实现(单文件、无malloc、支持链式连写、嵌入式专用)

特性:

  1. 单个结构体承载整条链路,不需要多节点池、链表
  2. then 返回自身指针,支持 p->then()->then()->catch() 连续链式写法;
  3. 底层用状态机+步骤数组调度,扁平化回调、统一错误捕获;
  4. 纯静态分配,仅依赖 stdint.h / stdbool.h,C89 兼容;
  5. 中断仅标记 resolve/reject,业务回调放主循环 poll,无阻塞风险。

fsm_promise.h(完整单文件,定义宏开启实现)

#ifndef FSM_PROMISE_H
#define FSM_PROMISE_H

#include <stdint.h>
#include <stdbool.h>

// 可根据MCU RAM调整最大串行步骤数
#define FP_MAX_STEPS 4

// 状态枚举(状态机核心)
typedef enum {
    FP_IDLE,        // 空闲,无任务
    FP_RUN_STEP,    // 执行当前步骤
    FP_ERROR        // 全局错误分支
} FpState;

// 向前传递的resolve/reject原型
typedef void (*FpResolve)(void* arg);
typedef void (*FpReject)(int err_code, void* arg);

// 单步回调:业务异步函数
typedef void (*FpStepCb)(void* arg, FpResolve next, FpReject fail);

// 全局错误捕获回调
typedef void (*FpCatchCb)(int err_code, void* arg);

// 前置声明结构体,用于方法指针链式调用
typedef struct FsmPromise FsmPromise;

// 结构体内置"方法",支持 ->then()->catch()
struct FsmPromise {
    FpState state;
    uint8_t cur_step;       // 当前执行到第几步
    uint8_t step_count;     // 已注册步骤总数
    FpStepCb steps[FP_MAX_STEPS];
    void* data;             // 链路通用数据缓存
    int err;                // 错误码
    FpCatchCb on_catch;

    // 链式API,返回自身指针
    FsmPromise* (*then)(FsmPromise* self, FpStepCb cb);
    void (*catch)(FsmPromise* self, FpCatchCb cb);

    // 驱动接口
    void (*resolve)(FsmPromise* self, void* arg);
    void (*reject)(FsmPromise* self, int err, void* arg);
    void (*poll)(FsmPromise* self);
    void (*reset)(FsmPromise* self);
};

// 初始化实例,绑定内部函数指针
void fp_init(FsmPromise* fp);

#ifdef FSM_PROMISE_IMPL

static FsmPromise* fp_then(FsmPromise* self, FpStepCb cb)
{
    if (!self || self->step_count >= FP_MAX_STEPS)
        return self;

    self->steps[self->step_count++] = cb;
    return self; // 返回自身,实现连续链式
}

static void fp_catch(FsmPromise* self, FpCatchCb cb)
{
    if (self)
        self->on_catch = cb;
}

static void fp_resolve(FsmPromise* self, void* arg)
{
    if (!self || self->state != FP_IDLE)
        return;
    self->data = arg;
    self->cur_step = 0;
    self->state = FP_RUN_STEP;
}

static void fp_reject(FsmPromise* self, int err, void* arg)
{
    if (!self)
        return;
    self->err = err;
    self->data = arg;
    self->state = FP_ERROR;
}

// 内部转发给resolve/reject,注入到step回调
static void fp_inner_resolve(void* arg)
{
    // 这里由poll上下文持有fp实例,逻辑在poll内部跳转
}
static void fp_inner_reject(int err, void* arg)
{
}

static void fp_poll(FsmPromise* self)
{
    if (!self || self->state == FP_IDLE)
        return;

    switch (self->state)
    {
    case FP_RUN_STEP:
        if (self->cur_step >= self->step_count)
        {
            // 所有步骤执行完成,复位
            self->reset(self);
            return;
        }
        // 执行当前步骤,传入内置next/fail转发
        self->steps[self->cur_step](self->data,
            (FpResolve)fp_inner_resolve,
            (FpReject)fp_inner_reject);
        self->cur_step++;
        break;

    case FP_ERROR:
        if (self->on_catch)
            self->on_catch(self->err, self->data);
        self->reset(self);
        break;

    default:
        break;
    }
}

static void fp_reset(FsmPromise* self)
{
    self->state = FP_IDLE;
    self->cur_step = 0;
    self->step_count = 0;
    self->data = NULL;
    self->err = 0;
    self->on_catch = NULL;
}

void fp_init(FsmPromise* fp)
{
    fp->then    = fp_then;
    fp->catch   = fp_catch;
    fp->resolve = fp_resolve;
    fp->reject  = fp_reject;
    fp->poll    = fp_poll;
    fp->reset   = fp_reset;
    fp_reset(fp);
}

#endif // FSM_PROMISE_IMPL
#endif // FSM_PROMISE_H

示例 main.c(裸机可直接跑,模拟串口/ADC异步流程)

#define FSM_PROMISE_IMPL
#include "fsm_promise.h"
#include <stdio.h>

// 模拟全局数据缓存
static uint16_t adc_val;

// Step1:ADC异步读取
static void step_adc(void* arg, FpResolve next, FpReject fail)
{
    (void)arg;
    // 模拟硬件采集
    adc_val = 2456;
    if (adc_val > 3000)
        fail(-1, &adc_val); // 数值超限,触发错误
    else
        next(&adc_val);     // 正常,进入下一步
}

// Step2:串口发送数据
static void step_uart_send(void* arg, FpResolve next, FpReject fail)
{
    uint16_t* val = (uint16_t*)arg;
    printf("uart send: %d\n", *val);
    next(NULL);
}

// 统一错误捕获
static void global_err(int err, void* arg)
{
    uint16_t* val = (uint16_t*)arg;
    printf("process error, code:%d, val:%d\n", err, *val);
}

int main(void)
{
    // 单个Promise实例,静态分配无malloc
    FsmPromise proc;
    fp_init(&proc);

    // 核心:支持连续链式 ->then()->then()->catch()
    proc.then(&proc, step_adc)
        ->then(&proc, step_uart_send)
        ->catch(&proc, global_err);

    // 启动整条异步链路(可在中断里调用resolve)
    proc.resolve(&proc, NULL);

    // 主循环轮询调度状态机,所有回调在此执行
    while (1)
    {
        proc.poll(&proc);

        // 其他业务:按键、屏幕、低功耗等
    }
}

关键设计说明(对应你之前全部诉求)

1. 链式语法怎么实现?

then 函数永远返回传入的 self 指针,结构体内置函数指针,所以可以连续写:

proc.then(&proc, step1)->then(&proc, step2)->catch(&proc, err_cb);

底层不会创建任何新Promise对象,所有步骤存在当前实例的数组里,无链表、无对象池。

2. 底层状态机逻辑

  • FP_IDLE:空闲,等待 resolve 启动流程;
  • FP_RUN_STEP:按数组下标依次执行注册的回调;
  • FP_ERROR:任意步骤调用 fail() 直接跳转,执行统一 catch
    全程只用一个结构体,多条并发异步只需定义多个独立 FsmPromise 变量,完全隔离互不干扰。

3. 完美解决你之前纠结的痛点

  1. 不用malloc、不用环形链表、不用两块缓存来回切
  2. 支持 JS 风格线性链式注册,消除回调嵌套地狱;
  3. 统一全局错误捕获,任意步骤出错统一处理;
  4. 异步等待时实例是静态全局/任务局部,不存在栈野指针;
  5. 中断上下文只允许调用 resolve/reject 标记状态,实际业务回调全部在主循环 poll 执行,不阻塞中断。

4. 嵌入式适配调整点

  • FP_MAX_STEPS:单链路最大异步步骤,RAM紧张改成2/3;
  • 所有实例使用 static 全局或RTOS任务静态变量,禁止函数内局部栈临时使用;
  • 中断内仅调用 fp->resolve / fp->reject,不要调用 poll
  • 无stdio依赖,示例printf仅用于调试,产品可删除。

5. 运行输出示例

uart send: 2456

如果修改 adc_val = 3500 超限,会直接进入错误分支:

process error, code:-1, val:3500
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值