examples/reference/c/eina/src/eina_future.c

297 lines
9.3 KiB
C
Raw Normal View History

#define EFL_EO_API_SUPPORT 1
#define EFL_BETA_API_SUPPORT 1
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <Eina.h>
#include <Efl_Core.h>
/*
* A collection of Eina Future examples.
* TEST 1: Set up a promised future and resolve it from a timer callback.
* TEST 2: Set up a promised future and reject it from a timer callback.
* TEST 3: Set up a promised future and then cancel it.
* TEST 4: Set up a chain of futures that get called one after the other when
* the promise is resolved, passing a value among them.
*/
static void _test1_simple_future(Efl_Loop *loop);
static void _test2_failed_future(Efl_Loop *loop);
static void _test3_cancelled_future(Efl_Loop *loop);
static void _test4_chained_future(Efl_Loop *loop);
/* ----------------------- Generic helper methods ---------------------- */
/*
* 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)
{
char *str = eina_value_to_string(&value);
printf(" Success callback: Promise resolved to '%s'\n", str);
free(str);
return value;
}
/*
* This will be called if a promise is cancelled.
*/
static void
_promise_cancel(void *data EINA_UNUSED, const Eina_Promise *dead EINA_UNUSED)
{
printf(" Promise cancellation callback: Promise cancelled\n");
}
/*
* 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(" Error callback: Promise encountered error '%s'\n",
eina_error_msg_get(error));
return EINA_VALUE_EMPTY;
}
/* ----------------------- Test 1 ---------------------- */
/* Resolve the promise passed through data to a string and cancel the timer */
static void
_test1_resolve(void *data, const Efl_Event *event)
{
Eina_Promise *promise = (Eina_Promise *)data;
eina_promise_resolve(promise, eina_value_string_init("Test 1 Delayed Value"));
efl_del(event->object);
}
/* Launches the next test */
static void
_test1_next_test(void *data, const Eina_Future *dead_future EINA_UNUSED)
{
Efl_Loop *loop = data;
printf(" Test 1 finished\n");
_test2_failed_future(loop);
}
/* TEST 1: Set up a promised future and resolve it from a timer callback */
static void
_test1_simple_future(Efl_Loop *loop)
{
Eina_Promise *promise;
// Create a promise
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
_promise_cancel, NULL);
printf("Test 1: Waiting for promise to be resolved...\n");
// This future will call _value_print() when the promise is resolved and
// execute the next test when the future is destroyed (for whatever reason)
eina_future_then_easy(eina_future_new(promise),
.success = _value_print,
.free = _test1_next_test,
.data = loop);
// Set up a regular timer that will trigger after 1s. We use it to
// simulate a delayed promise resolve.
efl_add(EFL_LOOP_TIMER_CLASS, loop,
efl_loop_timer_interval_set(efl_added, 1),
2019-03-09 06:54:38 -08:00
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TIMER_TICK,
_test1_resolve, promise));
}
/* ----------------------- Test 2 ---------------------- */
/* Reject the passed promise with an specific error and cancel the timer */
static void
_test2_reject(void *data, const Efl_Event *event)
{
Eina_Promise *promise = (Eina_Promise *)data;
2017-12-21 08:00:29 -08:00
eina_promise_reject(promise, EINA_ERROR_NOT_IMPLEMENTED);
efl_del(event->object);
}
/* Launches the next test */
static void
_test2_next_test(void *data, const Eina_Future *dead_future EINA_UNUSED)
{
Efl_Loop *loop = data;
printf(" Test 2 finished\n");
_test3_cancelled_future(loop);
}
/* TEST 2: Set up a promised future and reject it from a timer callback */
static void
_test2_failed_future(Efl_Loop *loop)
{
Eina_Promise *promise;
// Create a promise
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
_promise_cancel, NULL);
printf("Test 2: Waiting for promise to be rejected...\n");
// This future will call _value_print() when the promise is resolved.
// If there is an error, _error_print() is called instead.
// It then executes the next test when the future is destroyed.
eina_future_then_easy(eina_future_new(promise),
.success = _value_print,
.error = _error_print,
.free = _test2_next_test,
.data = loop);
// Set up a regular timer that will trigger after 1s. We use it to
// simulate a delayed promise rejection.
efl_add(EFL_LOOP_TIMER_CLASS, loop,
efl_loop_timer_interval_set(efl_added, 1),
2019-03-09 06:54:38 -08:00
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TIMER_TICK,
_test2_reject, promise));
}
/* ----------------------- Test 3 ---------------------- */
/* Launches the next test */
static void
_test3_next_test(void *data, const Eina_Future *dead_future EINA_UNUSED)
{
Efl_Loop *loop = data;
printf(" Test 3 finished\n");
_test4_chained_future(loop);
}
/* TEST 3: Set up a promised future and then cancel it */
static void
_test3_cancelled_future(Efl_Loop *loop)
{
Eina_Promise *promise;
Eina_Future *future;
// Create a promise
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
_promise_cancel, NULL);
future = eina_future_new(promise);
printf("Test 3: Waiting for promise to be cancelled...\n");
// This future will call _value_print() when the promise is resolved.
// If there is an error, _error_print() is called instead.
// It then executes the next test when the future is destroyed.
eina_future_then_easy(future,
.success = _value_print,
.error = _error_print,
.free = _test3_next_test,
.data = loop);
// Cancel the future before it has a chance to resolve
eina_future_cancel(future);
}
/* ----------------------- Test 4 ---------------------- */
/* Resolve the passed promise to an integer with value 1 and cancel the timer */
static void
_test4_resolve(void *data, const Efl_Event *event)
{
Eina_Promise *promise = (Eina_Promise *)data;
eina_promise_resolve(promise, eina_value_int_init(1));
efl_del(event->object);
}
/*
* A value callback to chain, taking in an int value and returning to chain
* the int multiplied by two.
*/
static Eina_Value
_chain_multiply_cb(void *data EINA_UNUSED, const Eina_Value value,
const Eina_Future *dead_future EINA_UNUSED)
{
int i;
if (value.type != EINA_VALUE_TYPE_INT)
{
fprintf(stderr, "Expected type 'int', got '%s'\n", value.type->name);
return value;
}
eina_value_get(&value, &i);
return *eina_value_util_int_new(i * 2);
}
/* This chained callback exits the example */
static Eina_Value
_exit_cb(void *data EINA_UNUSED, const Eina_Value value EINA_UNUSED,
const Eina_Future *dead_future EINA_UNUSED)
{
efl_exit(0);
printf(" Test 4 finished\n");
return EINA_VALUE_EMPTY;
}
/*
* TEST 4: Run a future chain where the initial future returns a single value.
* Each item in the chain then processes this value and passes it to the next item.
* 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
_test4_chained_future(Efl_Loop *loop)
{
Eina_Promise *promise;
// Create a promise
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
_promise_cancel, NULL);
printf("Test 4: Waiting for promise to be resolved...\n");
// All these methods, eina_future_cb_console() and _chain_multiply_cb(), will
// be called one after the other when the promise is resolved.
// Note how the last one is _exit_cb().
// There are 10 futures chained in total.
eina_future_chain(eina_future_new(promise),
eina_future_cb_console(" Starting chain with value: ", 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});
// Set up a regular timer that will trigger after 1s. We use it to
// simulate a delayed promise resolve.
efl_add(EFL_LOOP_TIMER_CLASS, loop,
efl_loop_timer_interval_set(efl_added, 1),
2019-03-09 06:54:38 -08:00
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TIMER_TICK,
_test4_resolve, promise));
}
/* ----------------------- Main ---------------------- */
EAPI_MAIN void
efl_main(void *data EINA_UNUSED, const Efl_Event *ev)
{
Efl_Loop *loop = ev->object;
// Start the first test, the others will be launched when this one finishes
_test1_simple_future(loop);
}
EFL_MAIN()