#ifndef KIT_ASYNC_FUNCTION_H #define KIT_ASYNC_FUNCTION_H #include "types.h" #include #ifdef __GNUC__ #define KIT_FALLTHROUGH __attribute__((fallthrough)); #else #define KIT_FALLTHROUGH #endif #ifdef __cplusplus extern "C" { #endif typedef struct { i32 _; } kit_af_void; typedef void (*kit_af_state_machine)(void *self_void_); #define KIT_AF_STATE_DATA \ struct { \ i32 _index; \ i32 _id; \ kit_af_state_machine _state_machine; \ } typedef struct { KIT_AF_STATE_DATA; } kit_af_type_void; #if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-function" # pragma GCC diagnostic ignored "-Wunknown-pragmas" #endif #define KIT_AF_INTERNAL(coro_) (*((kit_af_type_void *) (coro_))) #ifdef KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH // Application should implement this function if custom async // function dispatch is enabled. // // See KIT_ENABLE_CUSTOM_ASYNC_FUNCTION_DISPATCH macro. // void kit_async_function_dispatch(void *promise); #else static void kit_async_function_dispatch(void *promise) { // Dynamic dispatch by default. // KIT_AF_INTERNAL(promise)._state_machine(promise); } #endif #if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic pop #endif #define KIT_AF_STATE(ret_type_, name_, ...) \ struct name_##_coro_state_ { \ KIT_AF_STATE_DATA; \ ret_type_ return_value; \ __VA_ARGS__ \ } #define KIT_AF_DECL(name_) void name_(void *self_void_) #define KIT_CORO_IMPL(name_) \ KIT_AF_DECL(name_) { \ struct name_##_coro_state_ *self = \ (struct name_##_coro_state_ *) self_void_; \ switch (self->_index) { \ case 0:; #define KIT_AF_LINE_() __LINE__ #define KIT_CORO_END \ } \ self->_index = -1; \ } #define KIT_CORO_DECL(ret_type_, name_, ...) \ KIT_AF_STATE(ret_type_, name_, __VA_ARGS__); \ KIT_AF_DECL(name_) #define KIT_CORO(ret_type_, name_, ...) \ KIT_AF_STATE(ret_type_, name_, __VA_ARGS__); \ KIT_CORO_IMPL(name_) #define KIT_CORO_DECL_VOID(name_, ...) \ KIT_CORO_DECL(kit_af_void, name_, __VA_ARGS__) #define KIT_CORO_VOID(name_, ...) \ KIT_CORO(kit_af_void, name_, __VA_ARGS__) #define KIT_STATIC_CORO(ret_type_, name_, ...) \ KIT_AF_STATE(ret_type_, name_, __VA_ARGS__); \ static KIT_CORO_IMPL(name_) #define KIT_STATIC_CORO_VOID(name_, ...) \ KIT_STATIC_CORO(kit_af_void, name_, __VA_ARGS__) #define KIT_AF_EXECUTE(promise_) \ kit_async_function_dispatch(&(promise_)) #define KIT_AF_NEXT(promise_) \ (kit_async_function_dispatch(&(promise_)), (promise_).return_value) #define KIT_AF_YIELD(...) \ do { \ self->_index = KIT_AF_LINE_(); \ self->return_value = __VA_ARGS__; \ return; \ case KIT_AF_LINE_():; \ } while (0) #define KIT_AF_YIELD_VOID \ do { \ self->_index = KIT_AF_LINE_(); \ return; \ case KIT_AF_LINE_():; \ } while (0) #define KIT_AF_RETURN(...) \ do { \ self->_index = -1; \ self->return_value = __VA_ARGS__; \ return; \ } while (0) #define KIT_AF_RETURN_VOID \ do { \ self->_index = -1; \ return; \ } while (0) #define KIT_AF_AWAIT(promise_) \ do { \ KIT_FALLTHROUGH \ case KIT_AF_LINE_(): \ if ((promise_)._index != -1) { \ self->_index = KIT_AF_LINE_(); \ kit_async_function_dispatch(&(promise_)); \ } \ if ((promise_)._index != -1) \ return; \ } while (0) #define KIT_AF_YIELD_AWAIT(promise_) \ do { \ KIT_FALLTHROUGH \ case KIT_AF_LINE_(): \ if ((promise_)._index != -1) { \ self->_index = KIT_AF_LINE_(); \ kit_async_function_dispatch(&(promise_)); \ self->return_value = (promise_).return_value; \ return; \ } \ } while (0) #define KIT_AF_TYPE(coro_) struct coro_##_coro_state_ #define KIT_AF_INITIAL(id_, coro_) \ ._index = 0, ._id = (id_), ._state_machine = (coro_) #define KIT_AF_CREATE(promise_, coro_, ...) \ KIT_AF_TYPE(coro_) \ promise_ = { KIT_AF_INITIAL(0, coro_), __VA_ARGS__ } #define KIT_AF_CREATE_ID(promise_, id_, ...) \ KIT_AF_TYPE(coro_) \ promise_ = { KIT_AF_INITIAL(id_, NULL), __VA_ARGS__ } #define KIT_AF_INIT(promise_, coro_, ...) \ do { \ KIT_AF_CREATE(kit_af_temp_, coro_, __VA_ARGS__); \ memcpy(&(promise_), &kit_af_temp_, sizeof kit_af_temp_); \ } while (0) #define KIT_AF_INIT_ID(promise_, id_, ...) \ do { \ KIT_AF_CREATE_ID(kit_af_temp_, id_, __VA_ARGS__); \ memcpy(&(promise_), &kit_af_temp_, sizeof kit_af_temp_); \ } while (0) #define KIT_AF_FINISHED(promise_) ((promise_)._index == -1) #define KIT_AF_FINISHED_N(return_, promises_, size_) \ do { \ i32 kit_af_index_; \ (return_) = 1; \ for (kit_af_index_ = 0; kit_af_index_ < (size_); \ kit_af_index_++) \ if (!KIT_AF_FINISHED((promises_)[kit_af_index_])) { \ (return_) = 0; \ break; \ } \ } while (0) #define KIT_AF_FINISHED_ALL(return_, promises_) \ KIT_AF_FINISHED_N((return_), (promises_), \ sizeof(promises_) / sizeof((promises_)[0])) #ifdef __cplusplus } #endif #define af_void kit_af_void #define af_state_machine kit_af_state_machine #define af_type_void kit_af_type_void #define AF_STATE_DATA KIT_AF_STATE_DATA #define AF_STATE KIT_AF_STATE #define AF_DECL KIT_AF_DECL #define CORO_IMPL KIT_CORO_IMPL #define CORO_END KIT_CORO_END #define CORO_DECL KIT_CORO_DECL #define CORO KIT_CORO #define CORO_DECL_VOID KIT_CORO_DECL_VOID #define STATIC_CORO KIT_STATIC_CORO #define STATIC_CORO_VOID KIT_STATIC_CORO_VOID #define CORO_VOID KIT_CORO_VOID #define AF_EXECUTE KIT_AF_EXECUTE #define AF_NEXT KIT_AF_NEXT #define AF_YIELD KIT_AF_YIELD #define AF_YIELD_VOID KIT_AF_YIELD_VOID #define AF_RETURN KIT_AF_RETURN #define AF_RETURN_VOID KIT_AF_RETURN_VOID #define AF_AWAIT KIT_AF_AWAIT #define AF_YIELD_AWAIT KIT_AF_YIELD_AWAIT #define AF_TYPE KIT_AF_TYPE #define AF_INITIAL KIT_AF_INITIAL #define AF_CREATE KIT_AF_CREATE #define AF_INIT KIT_AF_INIT #define AF_FINISHED KIT_AF_FINISHED #define AF_FINISHED_N KIT_AF_FINISHED_N #define AF_FINISHED_ALL KIT_AF_FINISHED_ALL #endif