#define EFL_EO_API_SUPPORT 1 #define EFL_BETA_API_SUPPORT 1 #include #include #include #include #include /* * 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), 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; 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), 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), 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()