summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Sedov <radist.morse@gmail.com>2015-11-27 15:46:24 +0300
committerVictor Toso <me@victortoso.com>2016-01-30 11:59:16 +0100
commitd809be39ed2bbd4c410be7aa527b36902362511a (patch)
treef2eb8d07b300ff8300de420259893630708c517e
parent3e409b7727f803e2be4427c7544c679373a7d926 (diff)
lua-factory: change grl.callback(), grl.fetch() and grl.unzip()
This commit removes grl.callback() and changes the behavior of the grl.fetch() and grl.unzip(). The grl.callback function is now provided as a parameter to all the operations, and grl.fetch and grl.unzip now require callback as a lua function, not a string. Also, they now accept userdata. This commit finishes the work of removing the OperationSpec from the global scope. functions grl_lua_library_save/load/remove_operation_data and functions grl_lua_library_set/get_current_operation were removed functions grl_util_operation_spec_gc push_operation_spec_userdata and grl_lua_library_push_grl_callback were added https://bugzilla.gnome.org/show_bug.cgi?id=753141 Acked-by: Victor Toso <me@victortoso.com>
-rw-r--r--src/lua-factory/grl-lua-common.h9
-rw-r--r--src/lua-factory/grl-lua-factory.c34
-rw-r--r--src/lua-factory/grl-lua-library.c376
3 files changed, 199 insertions, 220 deletions
diff --git a/src/lua-factory/grl-lua-common.h b/src/lua-factory/grl-lua-common.h
index 4a369dc..603c139 100644
--- a/src/lua-factory/grl-lua-common.h
+++ b/src/lua-factory/grl-lua-common.h
@@ -76,21 +76,14 @@ typedef struct _OperationSpec {
GrlMedia *media;
gpointer user_data;
guint error_code;
- guint pending_ops;
gboolean callback_done;
} OperationSpec;
-void grl_lua_library_save_operation_data (lua_State *L, OperationSpec *os);
-void grl_lua_library_remove_operation_data (lua_State *L, guint operation_id);
-OperationSpec *grl_lua_library_load_operation_data (lua_State *L, guint operation_id);
-
-void grl_lua_library_set_current_operation (lua_State *L, guint operation_id);
-OperationSpec * grl_lua_library_get_current_operation (lua_State *L);
-
void grl_lua_library_save_goa_data (lua_State *L, gpointer goa_object);
gpointer grl_lua_library_load_goa_data (lua_State *L);
void grl_lua_library_push_grl_media (lua_State *L, GrlMedia *media);
void grl_lua_library_push_grl_options (lua_State *L, guint operation_id, GrlOperationOptions *options, GList *keys);
+void grl_lua_library_push_grl_callback (lua_State *L, OperationSpec *os);
#endif /* _GRL_LUA_LIBRARY_COMMON_H_ */
diff --git a/src/lua-factory/grl-lua-factory.c b/src/lua-factory/grl-lua-factory.c
index 13cccc5..888ce33 100644
--- a/src/lua-factory/grl-lua-factory.c
+++ b/src/lua-factory/grl-lua-factory.c
@@ -1498,20 +1498,18 @@ grl_lua_factory_source_search (GrlSource *source,
os->error_code = GRL_CORE_ERROR_SEARCH_FAILED;
os->op_type = LUA_SEARCH;
- grl_lua_library_save_operation_data (L, os);
- grl_lua_library_set_current_operation (L, os->operation_id);
lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_SEARCH]);
lua_pushstring (L, text);
grl_lua_library_push_grl_options (L, ss->operation_id, ss->options, ss->keys);
+ grl_lua_library_push_grl_callback (L, os);
- if (lua_pcall (L, 2, 0, 0)) {
+ if (lua_pcall (L, 3, 0, 0)) {
GRL_WARNING ("%s '%s'", "calling search function fail:",
lua_tolstring (L, -1, NULL));
lua_pop (L, 1);
}
-
- grl_lua_library_set_current_operation (L, 0);
+ lua_gc (L, LUA_GCCOLLECT, 0);
}
static void
@@ -1532,20 +1530,18 @@ grl_lua_factory_source_browse (GrlSource *source,
os->error_code = GRL_CORE_ERROR_BROWSE_FAILED;
os->op_type = LUA_BROWSE;
- grl_lua_library_save_operation_data (L, os);
- grl_lua_library_set_current_operation (L, os->operation_id);
lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_BROWSE]);
grl_lua_library_push_grl_media (L, bs->container);
grl_lua_library_push_grl_options (L, bs->operation_id, bs->options, bs->keys);
+ grl_lua_library_push_grl_callback (L, os);
- if (lua_pcall (L, 2, 0, 0)) {
+ if (lua_pcall (L, 3, 0, 0)) {
GRL_WARNING ("%s '%s'", "calling browse function fail:",
lua_tolstring (L, -1, NULL));
lua_pop (L, 1);
}
-
- grl_lua_library_set_current_operation (L, 0);
+ lua_gc (L, LUA_GCCOLLECT, 0);
}
static void
@@ -1569,20 +1565,18 @@ grl_lua_factory_source_query (GrlSource *source,
os->error_code = GRL_CORE_ERROR_QUERY_FAILED;
os->op_type = LUA_QUERY;
- grl_lua_library_save_operation_data (L, os);
- grl_lua_library_set_current_operation (L, os->operation_id);
lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_QUERY]);
lua_pushstring (L, query);
grl_lua_library_push_grl_options (L, qs->operation_id, qs->options, qs->keys);
+ grl_lua_library_push_grl_callback (L, os);
- if (lua_pcall (L, 2, 0, 0)) {
+ if (lua_pcall (L, 3, 0, 0)) {
GRL_WARNING ("%s '%s'", "calling query function fail:",
lua_tolstring (L, -1, NULL));
lua_pop (L, 1);
}
-
- grl_lua_library_set_current_operation (L, 0);
+ lua_gc (L, LUA_GCCOLLECT, 0);
}
static void
@@ -1595,8 +1589,6 @@ grl_lua_factory_source_resolve (GrlSource *source,
GRL_DEBUG ("grl_lua_factory_source_resolve");
- g_return_if_fail (grl_lua_library_load_operation_data (L, rs->operation_id) == NULL);
-
os = g_slice_new0 (OperationSpec);
os->source = rs->source;
os->operation_id = rs->operation_id;
@@ -1606,20 +1598,18 @@ grl_lua_factory_source_resolve (GrlSource *source,
os->error_code = GRL_CORE_ERROR_RESOLVE_FAILED;
os->op_type = LUA_RESOLVE;
- grl_lua_library_save_operation_data (L, os);
- grl_lua_library_set_current_operation (L, os->operation_id);
lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_RESOLVE]);
grl_lua_library_push_grl_media (L, rs->media);
grl_lua_library_push_grl_options (L, rs->operation_id, rs->options, rs->keys);
+ grl_lua_library_push_grl_callback (L, os);
- if (lua_pcall (L, 2, 0, 0)) {
+ if (lua_pcall (L, 3, 0, 0)) {
GRL_WARNING ("%s '%s'", "calling resolve function fail:",
lua_tolstring (L, -1, NULL));
lua_pop (L, 1);
}
-
- grl_lua_library_set_current_operation (L, 0);
+ lua_gc (L, LUA_GCCOLLECT, 0);
}
static gboolean
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 390b003..dbcb4cd 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -46,8 +46,8 @@ GRL_LOG_DOMAIN_STATIC (lua_library_log_domain);
typedef struct {
lua_State *L;
- guint operation_id;
- gchar *lua_cb;
+ gint lua_userdata;
+ gint lua_callback;
guint index;
gchar *url;
guint num_urls;
@@ -57,8 +57,8 @@ typedef struct {
typedef struct {
lua_State *L;
- guint operation_id;
- gchar *lua_cb;
+ gint lua_userdata;
+ gint lua_callback;
gchar *url;
gchar **filenames;
} UnzipOperation;
@@ -468,7 +468,6 @@ grl_util_fetch_done (GObject *source_object,
gsize len;
guint i;
GError *err = NULL;
- OperationSpec *os;
FetchOperation *fo = (FetchOperation *) user_data;
lua_State *L = fo->L;
gchar *fixed = NULL;
@@ -502,17 +501,14 @@ grl_util_fetch_done (GObject *source_object,
if (fo->results[i] == NULL) {
/* Clean up this operation, and wait for
* other operations to complete */
- g_free (fo->lua_cb);
+ g_free (fo->url);
g_free (fo);
return;
}
}
- grl_lua_library_set_current_operation (L, fo->operation_id);
- os = grl_lua_library_get_current_operation (L);
- os->pending_ops--;
-
- lua_getglobal (L, fo->lua_cb);
+ /* get the callback from the registry */
+ lua_rawgeti (L, LUA_REGISTRYINDEX, fo->lua_callback);
if (!fo->is_table) {
lua_pushlstring (L, fo->results[0], strlen (fo->results[0]));
@@ -525,18 +521,22 @@ grl_util_fetch_done (GObject *source_object,
}
}
- if (lua_pcall (L, 1, 0, 0)) {
- GRL_WARNING ("%s (%s) '%s'", "calling source callback function fail",
- fo->lua_cb, lua_tolstring (L, -1, NULL));
+ /* get userdata from the registry */
+ lua_rawgeti (L, LUA_REGISTRYINDEX, fo->lua_userdata);
+
+ if (lua_pcall (L, 2, 0, 0)) {
+ GRL_WARNING ("%s '%s'", "calling source callback function fail",
+ lua_tolstring (L, -1, NULL));
}
- grl_lua_library_set_current_operation (L, 0);
+ luaL_unref (L, LUA_REGISTRYINDEX, fo->lua_userdata);
+ luaL_unref (L, LUA_REGISTRYINDEX, fo->lua_callback);
+ lua_gc (L, LUA_GCCOLLECT, 0);
for (i = 0; i < fo->num_urls; i++)
g_free (fo->results[i]);
g_free (fo->url);
g_free (fo->results);
- g_free (fo->lua_cb);
g_free (fo);
}
@@ -627,7 +627,6 @@ grl_util_unzip_done (GObject *source_object,
gsize len;
guint i;
GError *err = NULL;
- OperationSpec *os;
UnzipOperation *uo = (UnzipOperation *) user_data;
lua_State *L = uo->L;
char **results;
@@ -648,11 +647,8 @@ grl_util_unzip_done (GObject *source_object,
results = get_zipped_contents ((guchar *) data, len, (const gchar **) uo->filenames);
}
- grl_lua_library_set_current_operation (L, uo->operation_id);
- os = grl_lua_library_get_current_operation (L);
- os->pending_ops--;
-
- lua_getglobal (L, uo->lua_cb);
+ /* get the callback from the registry */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, uo->lua_callback);
lua_newtable (L);
for (i = 0; results[i] != NULL; i++) {
@@ -661,24 +657,28 @@ grl_util_unzip_done (GObject *source_object,
lua_settable (L, -3);
}
- if (lua_pcall (L, 1, 0, 0)) {
- GRL_WARNING ("%s (%s) '%s'", "calling source callback function fail",
- uo->lua_cb, lua_tolstring (L, -1, NULL));
+ /* get userdata from the registry */
+ lua_rawgeti (L, LUA_REGISTRYINDEX, uo->lua_userdata);
+
+ if (lua_pcall (L, 2, 0, 0)) {
+ GRL_WARNING ("%s '%s'", "calling source callback function fail",
+ lua_tolstring (L, -1, NULL));
}
- grl_lua_library_set_current_operation (L, 0);
+ luaL_unref (L, LUA_REGISTRYINDEX, uo->lua_userdata);
+ luaL_unref (L, LUA_REGISTRYINDEX, uo->lua_callback);
+ lua_gc (L, LUA_GCCOLLECT, 0);
g_strfreev (results);
g_strfreev (uo->filenames);
- g_free (uo->lua_cb);
g_free (uo->url);
g_free (uo);
}
static GrlNetWc *
-net_wc_new_with_options(lua_State *L,
- guint arg_offset)
+net_wc_new_with_options (lua_State *L,
+ guint arg_offset)
{
GrlNetWc *wc;
@@ -882,8 +882,9 @@ grl_lua_library_push_grl_media (lua_State *L,
* grl.fetch
*
* @url: (string or array) The http url to GET the content.
-* @callback: (string) The function to be called after fetch is complete.
-* @netopts: (table) Options to set the GrlNetWc object.
+* @netopts: [optional] (table) Options to set the GrlNetWc object.
+* @callback: (function) The function to be called after fetch is complete.
+* @userdata: [optional] User data to be passed to the @callback.
* @return: Nothing.;
*/
static gint
@@ -893,22 +894,37 @@ grl_l_fetch (lua_State *L)
guint num_urls;
gchar **urls;
gchar **results;
- const gchar *lua_callback;
+ gint lua_userdata;
+ gint lua_callback;
GrlNetWc *wc;
gboolean is_table = FALSE;
- gboolean wc_options = FALSE;
- OperationSpec *os;
luaL_argcheck (L, (lua_isstring (L, 1) || lua_istable (L, 1)), 1,
"expecting url as string or an array of urls");
- luaL_argcheck (L, lua_isstring (L, 2), 2,
- "expecting callback function as string");
- /* Optional third argument */
- wc_options = (lua_gettop(L) == 3);
- os = grl_lua_library_get_current_operation (L);
- g_return_val_if_fail (os != NULL, 0);
- os->pending_ops++;
+ luaL_argcheck (L, (lua_isfunction (L, 2) || lua_istable (L, 2)), 2,
+ "expecting callback function or network parameters");
+
+ luaL_argcheck (L, (lua_isfunction (L, 2) ||
+ (lua_istable (L, 2) && lua_isfunction (L, 3))), 3,
+ "expecting callback function after network parameters");
+
+ /* keep arguments aligned */
+ if (lua_isfunction (L, 2)) {
+ lua_pushnil (L);
+ lua_insert (L, 2);
+ }
+
+ if (lua_gettop (L) > 4)
+ luaL_error (L, "too many arguments to 'fetch' function");
+
+ /* add nil if userdata is omitted */
+ lua_settop (L, 4);
+
+ /* pop the userdata and store it in registry */
+ lua_userdata = luaL_ref (L, LUA_REGISTRYINDEX);
+ /* pop the callback and store it in registry */
+ lua_callback = luaL_ref (L, LUA_REGISTRYINDEX);
num_urls = (lua_isstring (L, 1)) ? 1 : luaL_len (L, 1);
urls = g_new0 (gchar *, num_urls);
@@ -933,16 +949,18 @@ grl_l_fetch (lua_State *L)
}
if (!verify_plaintext_fetch (L, urls, num_urls)) {
- GRL_WARNING ("Source '%s' is broken, it makes plaintext network queries but "
- "does not set the 'net:plaintext' tag", grl_source_get_id (os->source));
+ GRL_WARNING ("Source is broken, it makes plaintext network queries but "
+ "does not set the 'net:plaintext' tag");
+
+ luaL_unref (L, LUA_REGISTRYINDEX, lua_userdata);
+ luaL_unref (L, LUA_REGISTRYINDEX, lua_callback);
+ lua_gc (L, LUA_GCCOLLECT, 0);
+
g_free (urls);
- os->pending_ops--;
- return 1;
+ return 0;
}
- lua_callback = lua_tolstring (L, 2, NULL);
-
- wc = (wc_options) ? net_wc_new_with_options(L, 3) : grl_net_wc_new ();
+ wc = net_wc_new_with_options (L, 2);
/* shared data between urls */
results = g_new0 (gchar *, num_urls);
@@ -951,8 +969,8 @@ grl_l_fetch (lua_State *L)
fo = g_new0 (FetchOperation, 1);
fo->L = L;
- fo->operation_id = os->operation_id;
- fo->lua_cb = g_strdup (lua_callback);
+ fo->lua_userdata = lua_userdata;
+ fo->lua_callback = lua_callback;
fo->index = i;
fo->url = g_strdup (urls[i]);
fo->num_urls = num_urls;
@@ -963,11 +981,11 @@ grl_l_fetch (lua_State *L)
}
g_object_unref (wc);
g_free (urls);
- return 1;
+ return 0;
}
/**
-* grl.callback
+* callback
*
* @media: (table) The media content to be returned.
* @count: (integer) Number of media remaining to the application.
@@ -978,16 +996,21 @@ grl_l_callback (lua_State *L)
{
gint nparam;
gint count = 0;
+ OperationSpec **p;
OperationSpec *os;
GrlMedia *media;
GRL_DEBUG ("grl.callback()");
+ g_return_val_if_fail (lua_isuserdata(L, lua_upvalueindex(1)), 0);
+ p = lua_touserdata (L, lua_upvalueindex(1));
+ os = *p;
+
nparam = lua_gettop (L);
- os = grl_lua_library_get_current_operation (L);
- if (os == NULL) {
- luaL_error (L, "Source is broken as grl.callback() was called "
- "after last operation has been finalized");
+
+ if (os->callback_done) {
+ luaL_error (L, "Source is broken as callback was called "
+ "after the operation has been finalized");
return 0;
}
@@ -1008,13 +1031,9 @@ grl_l_callback (lua_State *L)
count, os->user_data, NULL);
}
- /* Free Operation Spec */
- if (count == 0) {
+ /* finishing callback */
+ if (count == 0)
os->callback_done = TRUE;
- grl_lua_library_remove_operation_data (L, os->operation_id);
- grl_lua_library_set_current_operation (L, 0);
- g_slice_free (OperationSpec, os);
- }
return 0;
}
@@ -1156,17 +1175,18 @@ grl_l_unescape (lua_State *L)
*
* @url: (string) the URL of the zip file to fetch
* @filenames: (table) a table of filenames to get inside the zip file
- * @callback: (string) The function to be called after fetch is complete.
- * @netopts: (table) Options to set the GrlNetWc object.
+ * @netopts: [optional] (table) Options to set the GrlNetWc object.
+ * @callback: (function) The function to be called after fetch is complete.
+ * @userdata: [optional] User data to be passed to the @callback.
* @return: Nothing.;
*/
static gint
grl_l_unzip (lua_State *L)
{
- const gchar *lua_callback;
+ gint lua_userdata;
+ gint lua_callback;
const gchar *url;
GrlNetWc *wc;
- OperationSpec *os;
UnzipOperation *uo;
guint num_filenames, i;
gchar **filenames;
@@ -1175,12 +1195,28 @@ grl_l_unzip (lua_State *L)
"expecting url as string");
luaL_argcheck (L, lua_istable (L, 2), 2,
"expecting filenames as an array of filenames");
- luaL_argcheck (L, lua_isstring (L, 3), 3,
- "expecting callback function as string");
+ luaL_argcheck (L, (lua_isfunction (L, 3) || lua_istable (L, 3)), 3,
+ "expecting callback function or network parameters");
+ luaL_argcheck (L, (lua_isfunction (L, 3) ||
+ (lua_istable (L, 3) && lua_isfunction (L, 4))), 4,
+ "expecting callback function after network parameters");
+
+ /* keep arguments aligned */
+ if (lua_isfunction (L, 3)) {
+ lua_pushnil (L);
+ lua_insert (L, 3);
+ }
+
+ if (lua_gettop (L) > 5)
+ luaL_error (L, "too many arguments to 'unzip' function");
- os = grl_lua_library_get_current_operation (L);
- g_return_val_if_fail (os != NULL, 0);
- os->pending_ops++;
+ /* add nil if userdata is omitted */
+ lua_settop (L, 5);
+
+ /* pop the userdata and store it in registry */
+ lua_userdata = luaL_ref (L, LUA_REGISTRYINDEX);
+ /* pop the callback and store it in registry */
+ lua_callback = luaL_ref (L, LUA_REGISTRYINDEX);
url = lua_tolstring (L, 1, NULL);
num_filenames = luaL_len(L, 2);
@@ -1199,19 +1235,18 @@ grl_l_unzip (lua_State *L)
}
GRL_DEBUG ("grl.unzip() -> '%s'", url);
- lua_callback = lua_tolstring (L, 3, NULL);
- wc = net_wc_new_with_options (L, 4);
+ wc = net_wc_new_with_options (L, 3);
uo = g_new0 (UnzipOperation, 1);
uo->L = L;
- uo->operation_id = os->operation_id;
- uo->lua_cb = g_strdup (lua_callback);
+ uo->lua_userdata = lua_userdata;
+ uo->lua_callback = lua_callback;
uo->url = g_strdup (url);
uo->filenames = filenames;
grl_net_wc_request_async (wc, url, NULL, grl_util_unzip_done, uo);
g_object_unref (wc);
- return 1;
+ return 0;
}
/**
@@ -1353,7 +1388,6 @@ gint
luaopen_grilo (lua_State *L)
{
static const luaL_Reg library_fn[] = {
- {"callback", &grl_l_callback},
{"fetch", &grl_l_fetch},
{"debug", &grl_l_debug},
{"warning", &grl_l_warning},
@@ -1410,143 +1444,105 @@ luaopen_grilo (lua_State *L)
/* ======= Lua-Library and Lua-Factory utilities ============= */
/**
- * grl_lua_library_save_operation_data
+ * grl_util_operation_spec_gc
*
- * @L : LuaState where the data will be stored.
- * @os: The Operation Data to store.
- * @return: Nothing.
+ * This function is called when Lua GC is about to collect the userdata
+ * representing OperationSpec. Here we check that the finishing callback
+ * was done and free the memory.
*
- * Stores the OperationSpec from Lua-Factory in the global environment of
- * lua_State.
- **/
-void
-grl_lua_library_save_operation_data (lua_State *L, OperationSpec *os)
-{
- char *op_id;
-
- g_return_if_fail (os != NULL);
-
- op_id = g_strdup_printf (GRILO_LUA_OPERATION_INDEX "-%i", os->operation_id);
- lua_getglobal (L, LUA_ENV_TABLE);
- lua_pushstring (L, op_id);
- lua_pushlightuserdata (L, os);
- lua_settable (L, -3);
- lua_pop (L, 1);
- g_free (op_id);
-}
-
-/**
- * grl_lua_library_remove_operation_data
- *
- * @L: LuaState where the data will be removed.
- * @operation_id: The operation ID to remove.
- * @return: Nothing.
- *
- * Remove the OperationSpec with this ID from the the global environment of
- * lua_State.
+ * @L: LuaState where the data is stored.
+ * @return: 0, as the number of objects left on stack.
+ * It is important, for Lua stack to not be corrupted.
**/
-void
-grl_lua_library_remove_operation_data (lua_State *L, guint operation_id)
+static int
+grl_util_operation_spec_gc (lua_State *L)
{
- char *op_id;
+ OperationSpec **userdata = lua_touserdata (L, 1);
+ OperationSpec *os = *userdata;
- op_id = g_strdup_printf (GRILO_LUA_OPERATION_INDEX "-%i", operation_id);
- lua_getglobal (L, LUA_ENV_TABLE);
- lua_pushstring (L, op_id);
- lua_pushlightuserdata (L, NULL);
- lua_settable (L, -3);
- lua_pop (L, 1);
- g_free (op_id);
-}
+ if (os->callback_done == FALSE) {
-/**
- * grl_lua_library_load_operation_data
- *
- * @L : LuaState where the data is stored.
- * @operation_id: The operation ID to load Operation Data for.
- * to load the Operation Data for the current call.
- * @return: The Operation Data.
- **/
-OperationSpec *
-grl_lua_library_load_operation_data (lua_State *L, guint operation_id)
-{
- OperationSpec *os = NULL;
- char *op_id;
+ const char *type;
+ switch (os->op_type) {
+ case LUA_SEARCH:
+ type = "search";
+ break;
+ case LUA_BROWSE:
+ type = "browse";
+ break;
+ case LUA_QUERY:
+ type = "query";
+ break;
+ case LUA_RESOLVE:
+ type = "resolve";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
- g_return_val_if_fail (operation_id > 0, NULL);
+ GRL_WARNING ("Source '%s' is broken, as the finishing "
+ "callback was not called for %s operation", grl_source_get_id (os->source), type);
+ switch (os->op_type) {
+ case LUA_RESOLVE:
+ os->cb.resolve (os->source, os->operation_id, NULL, os->user_data, NULL);
+ break;
- op_id = g_strdup_printf (GRILO_LUA_OPERATION_INDEX "-%i", operation_id);
- lua_getglobal (L, LUA_ENV_TABLE);
- lua_pushstring (L, op_id);
- lua_gettable (L, -2);
- os = (lua_islightuserdata(L, -1)) ? lua_touserdata(L, -1) : NULL;
- lua_pop(L, 1);
- g_free (op_id);
+ default:
+ os->cb.result (os->source, os->operation_id, NULL,
+ 0, os->user_data, NULL);
+ }
+ }
- return os;
+ g_slice_free (OperationSpec, os);
+ *userdata = NULL;
+ return 0;
}
/**
- * grl_lua_library_set_current_operation
+ * push_operation_spec_userdata
+ *
+ * Creates a userdata on top of the Lua stack, with the GC function
+ * assigned to it.
*
* @L: LuaState where the data is stored.
- * @operation_id: The current operation ID.
- * @return: Nothing:
+ * @os: OperationSpec from which to create userdata.
+ * @return: Nothing.
**/
-void
-grl_lua_library_set_current_operation (lua_State *L, guint operation_id)
+static void
+push_operation_spec_userdata (lua_State *L, OperationSpec *os)
{
- OperationSpec *os;
-
- /* Verify that either grl.callback was called, or that there
- * are pending operations */
- os = grl_lua_library_get_current_operation (L);
- if (os) {
- if (os->pending_ops == 0 && !os->callback_done) {
- GRL_WARNING ("Source '%s' is broken, as there are no pending operations "
- "and grl.callback() was not called", grl_source_get_id (os->source));
- switch (os->op_type) {
- case LUA_RESOLVE:
- os->cb.resolve (os->source, os->operation_id, NULL, os->user_data, NULL);
- break;
-
- default:
- os->cb.result (os->source, os->operation_id, NULL,
- 0, os->user_data, NULL);
- }
- }
- }
-
- if (operation_id > 0)
- os = grl_lua_library_load_operation_data (L, operation_id);
- else
- os = NULL;
-
- lua_getglobal (L, LUA_ENV_TABLE);
- lua_pushstring (L, GRILO_LUA_OPERATION_INDEX);
- lua_pushlightuserdata (L, os);
+ OperationSpec **userdata = lua_newuserdata (L, sizeof (OperationSpec *));
+ *userdata = os;
+
+ /* create the metatable */
+ lua_createtable (L, 0, 1);
+ /* push the __gc key string */
+ lua_pushstring (L, "__gc");
+ /* push the __gc metamethod */
+ lua_pushcclosure (L, grl_util_operation_spec_gc, 0);
+ /* set the __gc field in the metatable */
lua_settable (L, -3);
- lua_pop (L, 1);
+ /* set table as the metatable of the userdata */
+ lua_setmetatable (L, -2);
}
/**
- * grl_lua_library_get_current_operation
+ * grl_lua_library_push_grl_callback
+ *
+ * Pushes two C closures on top of the lua stack, representing the
+ * callback and the options for the current operation.
*
* @L: LuaState where the data is stored.
- * @return: The Operation Data for the current operation.
+ * @os: OperationSpec the current operation.
+ * @return: Nothing.
**/
-OperationSpec *
-grl_lua_library_get_current_operation (lua_State *L)
+void
+grl_lua_library_push_grl_callback (lua_State *L, OperationSpec *os)
{
- OperationSpec *os = NULL;
-
- lua_getglobal (L, LUA_ENV_TABLE);
- lua_pushstring (L, GRILO_LUA_OPERATION_INDEX);
- lua_gettable (L, -2);
- os = (lua_islightuserdata(L, -1)) ? lua_touserdata(L, -1) : NULL;
- lua_pop(L, 1);
-
- return os;
+ /* push the OperationSpec userdata */
+ push_operation_spec_userdata (L, os);
+ /* use this userdata as an upvalue for the callback */
+ lua_pushcclosure (L, grl_l_callback, 1);
}
/**