ajwillia-ms pushed a commit to branch master. http://git.enlightenment.org/tools/examples.git/commit/?id=af48dd8fbae879b237360bfe4e77fd12eb15174b
commit af48dd8fbae879b237360bfe4e77fd12eb15174b Author: Andy Williams <a...@andywilliams.me> Date: Wed Dec 13 12:23:39 2017 +0000 eina: simplify and document our futures example --- reference/c/eina/src/eina_future.c | 333 +++++++++++++++++++------------------ 1 file changed, 168 insertions(+), 165 deletions(-) diff --git a/reference/c/eina/src/eina_future.c b/reference/c/eina/src/eina_future.c index 006e063..7e483af 100644 --- a/reference/c/eina/src/eina_future.c +++ b/reference/c/eina/src/eina_future.c @@ -14,231 +14,234 @@ * TODO */ -#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; \ - } - -typedef struct _Ctx { - Eina_Promise *p; - Eina_Bool should_fail; - Ecore_Timer *timer; - Eina_Value *value; -} Ctx; - +/* + * This will be called if a promise is cancelled + */ static void -_promise_cancel(void *data, const Eina_Promise *dead EINA_UNUSED) +_promise_cancel(void *data EINA_UNUSED, const Eina_Promise *dead EINA_UNUSED) { - Ctx *ctx = data; - if (ctx->timer) efl_del(ctx->timer); - eina_value_free(ctx->value); - free(ctx); + printf("Promise cancelled\n"); } -static Ctx * -_promise_ctx_new(Eina_Value *v) +/* + * This simple method prints the content of a value and passes it on + */ +static Eina_Value +_value_print(void *data EINA_UNUSED, const Eina_Value value) { - Ctx *ctx; - Efl_Loop *loop; - ctx = calloc(1, sizeof(Ctx)); - EINA_SAFETY_ON_NULL_GOTO(ctx, err_ctx); + printf("Found value %s\n", eina_value_to_string(&value)); - loop = efl_loop_main_get(EFL_LOOP_CLASS); - ctx->p = eina_promise_new(efl_loop_future_scheduler_get(loop), - _promise_cancel, ctx); - 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; + return value; } -static void -_timeout(void *data, const Efl_Event *event EINA_UNUSED) +/* + * This method will resolve the passed promise with a string value + */ +static Eina_Value +_delayed_value_resolve(void *data, const Eina_Value value EINA_UNUSED) { - Ctx *ctx = data; + Eina_Promise *promise; - if (ctx->should_fail) - { - eina_promise_reject(ctx->p, ENETDOWN); - } - else - { - Eina_Value v; - eina_value_copy(ctx->value, &v); - eina_promise_resolve(ctx->p, v); - eina_value_free(ctx->value); - } + promise = (Eina_Promise *)data; + eina_promise_resolve(promise, eina_value_string_init("Delayed Value :)")); - efl_del(ctx->timer); - free(ctx); + return EINA_VALUE_EMPTY; } -static Eina_Future * -_future_get(Ctx *ctx) +/* + * A simple future demo, set up a promised future + * and resolve it from a timer future. + */ +static void +_simple_future() { - Eina_Future *f; - - f = eina_future_new(ctx->p); - EINA_SAFETY_ON_NULL_GOTO(f, err_future); + Efl_Loop *loop; + Eina_Promise *promise; - efl_add(EFL_LOOP_TIMER_CLASS, NULL, - ctx->timer = efl_added, - efl_loop_timer_interval_set(efl_added, 0.1), - efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK, _timeout, ctx)); + // Create a demo promise for the sake of a trivial demo + loop = efl_loop_main_get(EFL_LOOP_CLASS); + promise = eina_promise_new(efl_loop_future_scheduler_get(loop), _promise_cancel, NULL); - EINA_SAFETY_ON_NULL_GOTO(ctx->timer, err_timer); - return f; + // Tis future will trigger a _value_print once resolved + eina_future_then_easy(eina_future_new(promise), .success = _value_print); - err_timer: - eina_future_cancel(f); - err_future: - return NULL; + // This future is basically a timer - wait 100ms and then resolve the promise above + eina_future_then_easy(efl_loop_timeout(efl_loop_main_get(EFL_LOOP_CLASS), 0.1), + .success = _delayed_value_resolve, .data = promise); } -static Eina_Future * -_fail_future_get(void) +/* + * This method prints the message of the error encountered and returns no value. + */ +static Eina_Value +_error_print(void *data EINA_UNUSED, const Eina_Error error) { - Ctx *ctx = _promise_ctx_new(NULL); - EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); - ctx->should_fail = EINA_TRUE; - return _future_get(ctx); + printf("Encountered error %s\n", eina_error_msg_get(error)); + + return EINA_VALUE_EMPTY; } -static Eina_Future * -_str_future_get(void) +/* + * This method will reject the passed promise with a "magic" error. + */ +static Eina_Value +_delayed_value_reject(void *data, const Eina_Value value EINA_UNUSED) { - Eina_Value *v = eina_value_util_string_new(DEFAULT_MSG); - EINA_SAFETY_ON_NULL_RETURN_VAL(v, NULL); - Ctx *ctx = _promise_ctx_new(v); - EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); - return _future_get(ctx); + Eina_Promise *promise; + + promise = (Eina_Promise *)data; + eina_promise_reject(promise, EINA_ERROR_MAGIC_FAILED); + + return EINA_VALUE_EMPTY; } -static Eina_Value -_simple_ok(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +/* + * A simple future failed demo, set up a promised future + * and reject it from a timer future. + */ +static void +_failed_future() { - VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_STRING); - return v; + Efl_Loop *loop; + Eina_Promise *promise; + + // Create a demo promise for the sake of a trivial demo + loop = efl_loop_main_get(EFL_LOOP_CLASS); + promise = eina_promise_new(efl_loop_future_scheduler_get(loop), _promise_cancel, NULL); + + // Tis future will trigger a _value_print once resolved + eina_future_then_easy(eina_future_new(promise), .error = _error_print); + + // This future is basically a timer - wait 100ms and then resolve the promise above + eina_future_then_easy(efl_loop_timeout(efl_loop_main_get(EFL_LOOP_CLASS), 0.1), + .success = _delayed_value_reject, .data = promise); } -static Eina_Value -_simple_err(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +/* + * A simple future failed demo, set up a promised future + * and reject it from a timer future. + */ +static void +_cancel_future() { - VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_ERROR); - return v; + Efl_Loop *loop; + Eina_Promise *promise; + Eina_Future *future; + + // Create a demo promise for the sake of a trivial demo + loop = efl_loop_main_get(EFL_LOOP_CLASS); + promise = eina_promise_new(efl_loop_future_scheduler_get(loop), _promise_cancel, NULL); + future = eina_future_new(promise); + + // Tis future will trigger a _value_print once resolved + eina_future_then_easy(future, .success = _value_print); + + // Then we cancel the future before it has a chance to resolve + eina_future_cancel(future); } +/* + * When our timeout is triggered we will resolve the promise passed. + * Set an int value to initialise the chain. + */ static void -_simple(void) +_timeout(void *data, const Efl_Event *event) { - eina_future_chain(_str_future_get(), - eina_future_cb_console("Expecting the following message: "DEFAULT_MSG "\n Got: ", NULL), - { .cb = _simple_ok, .data = NULL }); - eina_future_chain(_fail_future_get(), - eina_future_cb_console("Expecting network down error\n Got: ", NULL), - { .cb = _simple_err, .data = NULL }); + Eina_Promise *promise; + + promise = data; + eina_promise_resolve(promise, eina_value_int_init(1)); + + efl_del(event->object); } +/* + * Create a new int future that will resolve after a specified timer delay. + */ static Eina_Future * -_int_future_get(void) +_delayed_int_future_get(double delay) { - Eina_Value *v = eina_value_util_int_new(1); - EINA_SAFETY_ON_NULL_RETURN_VAL(v, NULL); - Ctx *ctx = _promise_ctx_new(v); - EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL); - return _future_get(ctx); + Efl_Loop *loop; + Eina_Promise *promise; + + // Create a demo promise for the sake of a trivial demo + loop = efl_loop_main_get(EFL_LOOP_CLASS); + promise = eina_promise_new(efl_loop_future_scheduler_get(loop), + _promise_cancel, NULL); + + efl_add(EFL_LOOP_TIMER_CLASS, NULL, + efl_loop_timer_interval_set(efl_added, delay), + efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK, + _timeout, promise)); + + return eina_future_new(promise); } +/* + * A value callback to chain, taking in an int value and returning to chain + * the int multiplied by two. + */ static Eina_Value -_chain_no_errors_cb(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +_chain_multiply_cb(void *data EINA_UNUSED, const Eina_Value v, + const Eina_Future *dead_future EINA_UNUSED) { int val; - VALUE_TYPE_CHECK(v, EINA_VALUE_TYPE_INT); - eina_value_get(&v, &val); + if (v.type != EINA_VALUE_TYPE_INT) + { + fprintf(stderr, "Incorrect type was returned"); + return v; + } + eina_value_get(&v, &val); return *eina_value_util_int_new(val * 2); } +/* + * This chained callback exits our example. + */ static Eina_Value -_exit_cb(void *data EINA_UNUSED, const Eina_Value v, const Eina_Future *dead_future EINA_UNUSED) +_exit_cb(void *data EINA_UNUSED, const Eina_Value v EINA_UNUSED, + const Eina_Future *dead_future EINA_UNUSED) { efl_exit(0); - return v; + return EINA_VALUE_EMPTY; } +/* + * Run a future chain where the initial future returns a single value. + * Each item in the chain then processes this value and passes on another. + * The _chain_multiply_cb returns twice the value it gets and the + * eina_future_cb_console prints a message including the value before passing + * it on. + */ static void -_chain_no_errors(void) -{ - eina_future_chain(_int_future_get(), - eina_future_cb_console("Expecting number 1\n Got: ", NULL), - {.cb = _chain_no_errors_cb, .data = NULL}, - eina_future_cb_console("Expecting number 2\n Got: ", NULL), - {.cb = _chain_no_errors_cb, .data = NULL}, - eina_future_cb_console("Expecting number 4\n Got: ", NULL), - {.cb = _chain_no_errors_cb, .data = NULL}, - eina_future_cb_console("Expecting number 8\n Got: ", NULL), - {.cb = _chain_no_errors_cb, .data = NULL}, - eina_future_cb_console("Expecting number 16\n Got: ", NULL), +_chained_future(void) +{ + eina_future_chain(_delayed_int_future_get(0.1), + eina_future_cb_console("Starting chain with: ", NULL), + {.cb = _chain_multiply_cb, .data = NULL}, + eina_future_cb_console(" Multiplied by 2: ", NULL), + {.cb = _chain_multiply_cb, .data = NULL}, + eina_future_cb_console(" Multiplied by 2: ", NULL), + {.cb = _chain_multiply_cb, .data = NULL}, + eina_future_cb_console(" Multiplied by 2: ", NULL), + {.cb = _chain_multiply_cb, .data = NULL}, + eina_future_cb_console(" Multiplied by 2: ", NULL), {.cb = _exit_cb, .data = 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(void) -{ - eina_future_chain(_int_future_get(), - { .cb=_chain_with_error_cb, .data=NULL }, - eina_future_cb_console("Expecting argument list too long. Got: ", NULL), - { .cb = _simple_err, .data = NULL }); - } - -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(void) -{ - Eina_Future *f; - - f = eina_future_chain(_int_future_get(), - 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); -} - +/* + * Run some futures examples. + */ EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) { - _simple(); - _chain_no_errors(); - _chain_with_error(); - _future_cancel(); + _simple_future(); + _failed_future(); + _cancel_future(); + _chained_future(); } EFL_MAIN() --