eina: simplify and document our futures example
This commit is contained in:
parent
54070a9226
commit
af48dd8fba
|
@ -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)
|
||||
{
|
||||
printf("Found value %s\n", eina_value_to_string(&value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
Eina_Promise *promise;
|
||||
|
||||
promise = (Eina_Promise *)data;
|
||||
eina_promise_resolve(promise, eina_value_string_init("Delayed Value :)"));
|
||||
|
||||
return EINA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple future demo, set up a promised future
|
||||
* and resolve it from a timer future.
|
||||
*/
|
||||
static void
|
||||
_simple_future()
|
||||
{
|
||||
Ctx *ctx;
|
||||
Efl_Loop *loop;
|
||||
ctx = calloc(1, sizeof(Ctx));
|
||||
EINA_SAFETY_ON_NULL_GOTO(ctx, err_ctx);
|
||||
Eina_Promise *promise;
|
||||
|
||||
// Create a demo promise for the sake of a trivial demo
|
||||
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;
|
||||
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), .success = _value_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_resolve, .data = promise);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
printf("Encountered error %s\n", eina_error_msg_get(error));
|
||||
|
||||
return EINA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_Promise *promise;
|
||||
|
||||
promise = (Eina_Promise *)data;
|
||||
eina_promise_reject(promise, EINA_ERROR_MAGIC_FAILED);
|
||||
|
||||
return EINA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple future failed demo, set up a promised future
|
||||
* and reject it from a timer future.
|
||||
*/
|
||||
static void
|
||||
_timeout(void *data, const Efl_Event *event EINA_UNUSED)
|
||||
_failed_future()
|
||||
{
|
||||
Ctx *ctx = data;
|
||||
Efl_Loop *loop;
|
||||
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);
|
||||
}
|
||||
// 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_del(ctx->timer);
|
||||
free(ctx);
|
||||
// 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_Future *
|
||||
_future_get(Ctx *ctx)
|
||||
/*
|
||||
* A simple future failed demo, set up a promised future
|
||||
* and reject it from a timer future.
|
||||
*/
|
||||
static void
|
||||
_cancel_future()
|
||||
{
|
||||
Eina_Future *f;
|
||||
Efl_Loop *loop;
|
||||
Eina_Promise *promise;
|
||||
Eina_Future *future;
|
||||
|
||||
f = eina_future_new(ctx->p);
|
||||
EINA_SAFETY_ON_NULL_GOTO(f, err_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
|
||||
_timeout(void *data, const Efl_Event *event)
|
||||
{
|
||||
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 *
|
||||
_delayed_int_future_get(double delay)
|
||||
{
|
||||
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,
|
||||
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));
|
||||
efl_loop_timer_interval_set(efl_added, delay),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK,
|
||||
_timeout, promise));
|
||||
|
||||
EINA_SAFETY_ON_NULL_GOTO(ctx->timer, err_timer);
|
||||
return f;
|
||||
|
||||
err_timer:
|
||||
eina_future_cancel(f);
|
||||
err_future:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Eina_Future *
|
||||
_fail_future_get(void)
|
||||
{
|
||||
Ctx *ctx = _promise_ctx_new(NULL);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
||||
ctx->should_fail = EINA_TRUE;
|
||||
return _future_get(ctx);
|
||||
}
|
||||
|
||||
static Eina_Future *
|
||||
_str_future_get(void)
|
||||
{
|
||||
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);
|
||||
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
|
||||
_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
|
||||
_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(void)
|
||||
{
|
||||
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 });
|
||||
}
|
||||
|
||||
static Eina_Future *
|
||||
_int_future_get(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
_chained_future(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),
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue