Overhaul of the Eina_Future example
Run tests consecutively, triggering next one on the future's free callback. Label test numbers explicitly, code reordering and beautifying. Some console output beautifying too.
This commit is contained in:
parent
348ea10272
commit
11091214f7
|
@ -9,67 +9,42 @@
|
|||
#include <Efl_Core.h>
|
||||
|
||||
/*
|
||||
* Eina Future examples.
|
||||
*
|
||||
* TODO
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 cancelled\n");
|
||||
}
|
||||
static void _test1_simple_future();
|
||||
static void _test2_failed_future();
|
||||
static void _test3_cancelled_future();
|
||||
static void _test4_chained_future();
|
||||
|
||||
/* ----------------------- Generic helper methods ---------------------- */
|
||||
|
||||
/*
|
||||
* This simple method prints the content of a value and passes it on
|
||||
* 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)
|
||||
_value_print(void *data, const Eina_Value value)
|
||||
{
|
||||
printf("Found value %s\n", eina_value_to_string(&value));
|
||||
Eina_Promise *promise = (Eina_Promise *)data;
|
||||
char *str = eina_value_to_string(&value);
|
||||
printf(" Success callback: Promise %p resolved to '%s'\n", promise, str);
|
||||
free(str);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method will resolve the passed promise with a string value
|
||||
* This will be called if a promise is cancelled.
|
||||
*/
|
||||
static void
|
||||
_delayed_value_resolve(void *data, const Efl_Event *event)
|
||||
_promise_cancel(void *data EINA_UNUSED, const Eina_Promise *dead EINA_UNUSED)
|
||||
{
|
||||
Eina_Promise *promise;
|
||||
|
||||
promise = (Eina_Promise *)data;
|
||||
eina_promise_resolve(promise, eina_value_string_init("Delayed Value :)"));
|
||||
|
||||
efl_del(event->object);
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple future demo, set up a promised future
|
||||
* and resolve it from a timer future.
|
||||
*/
|
||||
static void
|
||||
_simple_future()
|
||||
{
|
||||
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), .success = _value_print);
|
||||
|
||||
// This future is basically a timer - wait 100ms and then resolve the promise above
|
||||
efl_add(EFL_LOOP_TIMER_CLASS, loop,
|
||||
efl_loop_timer_interval_set(efl_added, 0.1),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK,
|
||||
_delayed_value_resolve, promise));
|
||||
printf(" Promise cancellation callback: Promise %p cancelled\n", dead);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -78,105 +53,162 @@ _simple_future()
|
|||
static Eina_Value
|
||||
_error_print(void *data EINA_UNUSED, const Eina_Error error)
|
||||
{
|
||||
printf("Encountered error %s\n", eina_error_msg_get(error));
|
||||
Eina_Promise *promise = (Eina_Promise *)data;
|
||||
printf(" Error callback: Promise %p encountered error '%s'\n", promise,
|
||||
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;
|
||||
/* ----------------------- Test 1 ---------------------- */
|
||||
|
||||
promise = (Eina_Promise *)data;
|
||||
eina_promise_reject(promise, EINA_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
return EINA_VALUE_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple future failed demo, set up a promised future
|
||||
* and reject it from a timer future.
|
||||
*/
|
||||
/* Resolve the promise passed through data to a string and cancel the timer */
|
||||
static void
|
||||
_failed_future()
|
||||
_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 EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
printf(" Test 1 finished\n");
|
||||
_test2_failed_future();
|
||||
}
|
||||
|
||||
/* 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 demo promise for the sake of a trivial demo
|
||||
// Create a promise
|
||||
loop = efl_loop_main_get(EFL_LOOP_CLASS);
|
||||
promise = eina_promise_new(efl_loop_future_scheduler_get(loop), _promise_cancel, NULL);
|
||||
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
|
||||
_promise_cancel, NULL);
|
||||
printf("Test 1: Waiting for promise %p to be resolved...\n", promise);
|
||||
|
||||
// Tis future will trigger a _value_print once resolved
|
||||
eina_future_then_easy(eina_future_new(promise), .error = _error_print);
|
||||
// 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 = promise);
|
||||
|
||||
// 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.2),
|
||||
.success = _delayed_value_reject, .data = promise);
|
||||
// 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),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK,
|
||||
_test1_resolve, promise));
|
||||
}
|
||||
|
||||
/*
|
||||
* A simple future failed demo, set up a promised future
|
||||
* and reject it from a timer future.
|
||||
*/
|
||||
/* ----------------------- Test 2 ---------------------- */
|
||||
|
||||
/* Reject the passed promise with an specific error and cancel the timer */
|
||||
static void
|
||||
_cancel_future()
|
||||
_test2_reject(void *data, const Efl_Event *event)
|
||||
{
|
||||
Eina_Promise *promise = (Eina_Promise *)data;
|
||||
|
||||
eina_promise_reject(promise, EINA_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
efl_del(event->object);
|
||||
}
|
||||
|
||||
/* Launches the next test */
|
||||
static void
|
||||
_test2_next_test(void *data EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
printf(" Test 2 finished\n");
|
||||
_test3_cancelled_future();
|
||||
}
|
||||
|
||||
/* 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
|
||||
loop = efl_loop_main_get(EFL_LOOP_CLASS);
|
||||
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
|
||||
_promise_cancel, NULL);
|
||||
printf("Test 2: Waiting for promise %p to be rejected...\n", promise);
|
||||
|
||||
// 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 = promise);
|
||||
|
||||
// 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),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK,
|
||||
_test2_reject, promise));
|
||||
}
|
||||
|
||||
/* ----------------------- Test 3 ---------------------- */
|
||||
|
||||
/* Launches the next test */
|
||||
static void
|
||||
_test3_next_test(void *data EINA_UNUSED, const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
printf(" Test 3 finished\n");
|
||||
_test4_chained_future();
|
||||
}
|
||||
|
||||
/* 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 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
|
||||
// Create a promise
|
||||
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);
|
||||
printf("Test 3: Waiting for promise %p to be cancelled...\n", promise);
|
||||
|
||||
efl_add(EFL_LOOP_TIMER_CLASS, loop,
|
||||
efl_loop_timer_interval_set(efl_added, delay),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK,
|
||||
_timeout, promise));
|
||||
// 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 = promise);
|
||||
|
||||
return eina_future_new(promise);
|
||||
// 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -184,45 +216,58 @@ _delayed_int_future_get(double delay)
|
|||
* the int multiplied by two.
|
||||
*/
|
||||
static Eina_Value
|
||||
_chain_multiply_cb(void *data EINA_UNUSED, const Eina_Value v,
|
||||
_chain_multiply_cb(void *data EINA_UNUSED, const Eina_Value value,
|
||||
const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
int val;
|
||||
int i;
|
||||
|
||||
if (v.type != EINA_VALUE_TYPE_INT)
|
||||
if (value.type != EINA_VALUE_TYPE_INT)
|
||||
{
|
||||
fprintf(stderr, "Incorrect type was returned");
|
||||
return v;
|
||||
fprintf(stderr, "Expected type 'int', got '%s'\n", value.type->name);
|
||||
return value;
|
||||
}
|
||||
|
||||
eina_value_get(&v, &val);
|
||||
return *eina_value_util_int_new(val * 2);
|
||||
eina_value_get(&value, &i);
|
||||
return *eina_value_util_int_new(i * 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* This chained callback exits our example.
|
||||
*/
|
||||
/* This chained callback exits the example */
|
||||
static Eina_Value
|
||||
_exit_cb(void *data EINA_UNUSED, const Eina_Value v EINA_UNUSED,
|
||||
_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
_chained_future(void)
|
||||
_test4_chained_future(void)
|
||||
{
|
||||
eina_future_chain(_delayed_int_future_get(0.5),
|
||||
eina_future_cb_console("Starting chain with: ", NULL),
|
||||
Efl_Loop *loop;
|
||||
Eina_Promise *promise;
|
||||
|
||||
// Create a promise
|
||||
loop = efl_loop_main_get(EFL_LOOP_CLASS);
|
||||
promise = eina_promise_new(efl_loop_future_scheduler_get(loop),
|
||||
_promise_cancel, NULL);
|
||||
|
||||
printf("Test 4: Waiting for promise %p to be resolved...\n", promise);
|
||||
// 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},
|
||||
|
@ -232,18 +277,22 @@ _chained_future(void)
|
|||
{.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),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_TIMER_EVENT_TICK,
|
||||
_test4_resolve, promise));
|
||||
}
|
||||
|
||||
/*
|
||||
* Run some futures examples.
|
||||
*/
|
||||
/* ----------------------- Main ---------------------- */
|
||||
|
||||
EAPI_MAIN void
|
||||
efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
_simple_future();
|
||||
_failed_future();
|
||||
_cancel_future();
|
||||
_chained_future();
|
||||
// Start the first test, the others will be launched when this one finishes
|
||||
_test1_simple_future();
|
||||
}
|
||||
|
||||
EFL_MAIN()
|
||||
|
|
Loading…
Reference in New Issue