#define EFL_BETA_API_SUPPORT 1 #include #include #include typedef struct _Ctx { Eina_Promise *p; Eina_Bool should_fail; Eina_Future *timer; Eina_Value *value; } Ctx; typedef struct _Inner_Promise_Ctx { Eina_Future *future; Eina_Promise *promise; } Inner_Promise_Ctx; #define DEFAULT_MSG "the simple example is working!" #define VALUE_TYPE_CHECK(_v, _type) \ if (_v.type != _type) \ { \ fprintf(stderr, "Value type is not '%s' - received '%s'\n", \ _type->name, _v.type->name); \ return _v; \ } static Eina_Value _timeout(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { Ctx *ctx = data; if (v.type == EINA_VALUE_TYPE_ERROR) goto end; if (ctx->should_fail) eina_promise_reject(ctx->p, ENETDOWN); else { Eina_Value tmp; eina_value_copy(ctx->value, &tmp); eina_promise_resolve(ctx->p, tmp); } end: if (ctx->value) eina_value_free(ctx->value); ctx->timer = NULL; free(ctx); return v; } static Eina_Value _promise_cancel(Eo *o EINA_UNUSED, void *data, Eina_Error error) { Ctx *ctx = data; if (error == ECANCELED && ctx->timer) eina_future_cancel(ctx->timer); return eina_value_error_init(error); } static Ctx * _promise_ctx_new(Efl_Loop *loop, Eina_Value *v) { Ctx *ctx; ctx = calloc(1, sizeof(Ctx)); EINA_SAFETY_ON_NULL_GOTO(ctx, err_ctx); ctx->p = efl_loop_promise_new(loop); EINA_SAFETY_ON_NULL_GOTO(ctx->p, err_timer); ctx->value = v; return ctx; err_timer: free(ctx); err_ctx: eina_value_free(v); return NULL; } static Eina_Future * _future_get(Ctx *ctx, Efl_Loop *loop) { Eina_Future *f; f = eina_future_new(ctx->p); EINA_SAFETY_ON_NULL_GOTO(f, err_future); ctx->timer = eina_future_then(efl_loop_timeout(loop, 0.1), _timeout, ctx); EINA_SAFETY_ON_NULL_GOTO(ctx->timer, err_timer); return efl_future_then(loop, f, .error = _promise_cancel, .data = ctx); err_timer: eina_future_cancel(f); err_future: return NULL; } static Eina_Future * _fail_future_get(Efl_Loop *loop) { Ctx *ctx = _promise_ctx_new(loop, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); ctx->should_fail = EINA_TRUE; return _future_get(ctx, loop); } static Eina_Future * _str_future_get(Efl_Loop *loop) { Eina_Value *v = eina_value_util_string_new(DEFAULT_MSG); EINA_SAFETY_ON_NULL_RETURN_VAL(v, NULL); Ctx *ctx = _promise_ctx_new(loop, v); EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); return _future_get(ctx, loop); } static Eina_Future * _int_future_get(Efl_Loop *loop, int i) { Eina_Value *v = eina_value_util_int_new(i); EINA_SAFETY_ON_NULL_RETURN_VAL(v, NULL); Ctx *ctx = _promise_ctx_new(loop, v); EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); return _future_get(ctx, loop); } static Eina_Value _simple_ok(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING); return v; } static Eina_Value _alternate_error_cb(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { Eina_Bool *should_fail = data; Eina_Value new_v = EINA_VALUE_EMPTY; if (*should_fail) { *should_fail = EINA_FALSE; eina_value_setup(&new_v, EINA_VALUE_TYPE_ERROR); eina_value_set(&new_v, ENETDOWN); printf("Received succes from the previous future - Generating error for the next future...\n"); } else { *should_fail = EINA_TRUE; Eina_Error err; VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR); eina_value_get(&v, &err); printf("Received error from the previous future - value: %s. Send success\n", eina_error_msg_get(err)); } return new_v; } static void _alternate_error(Efl_Loop *loop) { static Eina_Bool should_fail = EINA_TRUE; eina_future_chain(_str_future_get(loop), {.cb = _alternate_error_cb, .data = &should_fail}, {.cb = _alternate_error_cb, .data = &should_fail}, {.cb = _alternate_error_cb, .data = &should_fail}, {.cb = _alternate_error_cb, .data = &should_fail}); } static Eina_Value _simple_err(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR); return v; } static void _simple(Efl_Loop *loop) { eina_future_chain(_str_future_get(loop), eina_future_cb_console("Expecting the following message: "DEFAULT_MSG ". Got: ", NULL), { .cb = _simple_ok, .data = NULL }); eina_future_chain(_fail_future_get(loop), eina_future_cb_console("Expectig network down error. Got: ", NULL), { .cb = _simple_err, .data = NULL }); } static Eina_Value _chain_no_errors_cb(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { int count; Eina_Value new_v; eina_value_setup(&new_v, EINA_VALUE_TYPE_INT); if (!v.type) count = 1; else { VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT); eina_value_get(&v, &count); } eina_value_set(&new_v, count * 2); return new_v; } static void _chain_no_errors(Efl_Loop *loop) { eina_future_chain(_int_future_get(loop, 0), eina_future_cb_console("Expecting no value. Got: ", NULL), {.cb = _chain_no_errors_cb, .data = NULL}, eina_future_cb_console("Expecting number 2. Got: ", NULL), {.cb = _chain_no_errors_cb, .data = NULL}, eina_future_cb_console("Expecting number 4. Got: ", NULL), {.cb = _chain_no_errors_cb, .data = NULL}, eina_future_cb_console("Expecting number 8. Got: ", NULL), {.cb = _chain_no_errors_cb, .data = NULL}, eina_future_cb_console("Expecting number 16. Got: ", NULL)); } static Eina_Value _chain_with_error_cb(void *data EINA_UNUSED, const Eina_Value v EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED) { Eina_Value err; eina_value_setup(&err, EINA_VALUE_TYPE_ERROR); eina_value_set(&err, E2BIG); return err; } static void _chain_with_error(Efl_Loop *loop) { eina_future_chain(_int_future_get(loop, 0), { _chain_with_error_cb, NULL }, eina_future_cb_console("Expecting argument list too long. Got: ", NULL), { .cb = _simple_err, .data = NULL }); } static Eina_Value _delayed_resolve(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { Inner_Promise_Ctx *ctx = data; Eina_Value new_v; eina_value_setup(&new_v, EINA_VALUE_TYPE_STRING); eina_value_set(&new_v, "Hello from inner future"); eina_promise_resolve(ctx->promise, new_v); free(ctx); return v; } static Eina_Value _delayed_reject(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { Inner_Promise_Ctx *ctx = data; eina_promise_reject(ctx->promise, ENETDOWN); free(ctx); return v; } static void _inner_promise_cancel(void *data, const Eina_Promise *dead EINA_UNUSED) { Inner_Promise_Ctx *ctx = data; eina_future_cancel(ctx->future); free(ctx); } static Eina_Value _chain_inner_cb(void *data, const Eina_Value v, const Eina_Future *dead_future) { Inner_Promise_Ctx *ctx; Eina_Value r; int s = 0; eina_value_int_get(&v, &s); ctx = calloc(1, sizeof(Inner_Promise_Ctx)); EINA_SAFETY_ON_NULL_GOTO(ctx, err); ctx->promise = eina_promise_continue_new(dead_future, _inner_promise_cancel, ctx); EINA_SAFETY_ON_NULL_GOTO(ctx->promise, err); printf("Creating a new promise inside the future cb\n"); ctx->future = eina_future_then(_int_future_get(data, 0), !s ? _delayed_resolve : _delayed_reject, ctx); return eina_promise_as_value(ctx->promise); err: eina_value_setup(&r, EINA_VALUE_TYPE_ERROR); eina_value_set(&r, ENOMEM); free(ctx); return r; } static Eina_Value _chain_inner_last_cb(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING); return v; } static void _chain_inner_no_errors(Efl_Loop *loop) { eina_future_chain(_int_future_get(loop, 0), { .cb = _chain_inner_cb, .data = loop }, eina_future_cb_console("Expecting message: 'Hello from inner future'. Got: ", NULL), { .cb = _chain_inner_last_cb, .data = NULL }); } static Eina_Value _err_inner_chain(void *data, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR); efl_loop_quit(data, EINA_VALUE_EMPTY); return v; } static void _chain_inner_errors(Efl_Loop *loop) { eina_future_chain(_int_future_get(loop, 1), { .cb = _chain_inner_cb, .data = loop }, eina_future_cb_console("Expection network down error. Got: ", NULL), { .cb = _err_inner_chain, .data = loop }); } static Eina_Value _canceled_cb(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) { VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR); return v; } static void _future_cancel(Efl_Loop *loop) { Eina_Future *f; f = eina_future_chain(_int_future_get(loop, 0), eina_future_cb_console("Expecting cancelled operation error. Got: ", NULL), { .cb = _canceled_cb, .data = NULL }, eina_future_cb_console("Expecting cancelled operation error. Got: ", NULL), { .cb = _canceled_cb, .data = NULL }, eina_future_cb_console("Expecting cancelled operation error. Got: ", NULL), { .cb = _canceled_cb, .data = NULL }, eina_future_cb_console("Expecting cancelled operation error. Got: ", NULL), { .cb = _canceled_cb, .data = NULL }, eina_future_cb_console("Expecting cancelled operation error. Got: ", NULL), { .cb = _canceled_cb, .data = NULL }, eina_future_cb_console("Expecting cancelled operation error. Got: ", NULL)); eina_future_cancel(f); } EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev) { _simple(ev->object); _alternate_error(ev->object); _chain_no_errors(ev->object); _chain_with_error(ev->object); _chain_inner_no_errors(ev->object); _chain_inner_errors(ev->object); _future_cancel(ev->object); } EFL_MAIN();