replace lua_client_networks/lua_network_channels with iterators
authorTero Marttila <terom@fixme.fi>
Thu, 14 May 2009 22:57:13 +0300
changeset 199 8eb839fbabba
parent 198 b74185e1357a
child 200 c414343101df
replace lua_client_networks/lua_network_channels with iterators
src/lua_func.c
src/lua_func.h
src/lua_irc.c
src/lua_type.c
--- a/src/lua_func.c	Thu May 14 21:45:43 2009 +0300
+++ b/src/lua_func.c	Thu May 14 22:57:13 2009 +0300
@@ -70,6 +70,19 @@
     return lua_toboolean(L, index);
 }
 
+static void * _lua_arg_obj (lua_State *L, int index, const struct lua_type *type, bool optional)
+{
+    // not given?
+    if (!lua_isnoneornil(L, index))
+        return lua_type_get(L, type, index);
+
+    if (optional)
+        return NULL;
+    
+    luaL_error(L, "missing value for required object argument <%d:%s>", index, type->name);
+    return NULL;
+}
+
 /**
  * Look up the arg index to use for the given index/name.
  *
@@ -78,8 +91,8 @@
 static int lua_arg_index (lua_State *L, int nargs, int index, const char *name)
 {
     // lookup from table?
-    if (name && lua_istable(L, 2)) {
-        // push the value from the field onto the stack
+    if (nargs == 2 && lua_istable(L, 2) && name) {
+        // push the value from the named field onto the stack
         lua_getfield(L, 2, name);
         
         // no named field?
@@ -119,6 +132,11 @@
     return _lua_arg_bool(L, lua_arg_index(L, nargs, index, name), name, def);    
 }
 
+void * lua_arg_obj (lua_State *L, int nargs, int index, const struct lua_type *type, bool optional)
+{
+    return _lua_arg_obj(L, lua_arg_index(L, nargs, index, NULL), type, optional);
+}
+
 void lua_args_parse (lua_State *L, const struct lua_func *func, void **obj_ptr, ...)
 {
     int argidx = 1, argtbl = 0, idx;
--- a/src/lua_func.h	Thu May 14 21:45:43 2009 +0300
+++ b/src/lua_func.h	Thu May 14 22:57:13 2009 +0300
@@ -82,6 +82,11 @@
 bool lua_arg_bool (lua_State *L, int nargs, int index, const char *name, int def);
 
 /**
+ * Return a userdata argument at the given fixed index
+ */
+void * lua_arg_obj (lua_State *L, int nargs, int index, const struct lua_type *type, bool optional);
+
+/**
  * Parse function arguments as defined
  */
 void lua_args_parse (lua_State *L, const struct lua_func *func, void **obj_ptr, ...);
--- a/src/lua_irc.c	Thu May 14 21:45:43 2009 +0300
+++ b/src/lua_irc.c	Thu May 14 22:57:13 2009 +0300
@@ -172,37 +172,48 @@
 }
 
 static struct lua_func lua_net_channels_func = LUA_FUNC(&lua_net_type, "channels",
-        "return a list of channel objects",
+        "Return an iterater over the network's channels",
         
         LUA_FUNC_ARG_END
     );
 
+static int lua_net_channels_iter (lua_State *L)
+{
+    int nargs = lua_gettop(L);
+    struct lua_net *lua_net = lua_arg_obj(L, nargs, 1, &lua_net_type, false);
+    struct lua_chan *lua_chan = lua_arg_obj(L, nargs, 2, &lua_chan_type, true);
+    struct irc_chan *chan_next;
+
+    // get next item from current
+    if (lua_chan)
+        chan_next = TAILQ_NEXT(lua_chan->chan, net_channels);
+    else
+        chan_next = TAILQ_FIRST(&lua_net->net->channels);
+
+    // push return value - next item
+    if (chan_next)
+        lua_chan_create(L, chan_next);
+    else
+        lua_pushnil(L);
+
+    return 1;
+}
+
 static int lua_net_channels (lua_State *L)
 {
     struct lua_net *lua_net;
-    struct irc_chan *chan;
-    int i = 1;
 
     // parse args
     lua_args_parse(L, &lua_net_channels_func, (void *) &lua_net);
 
-    // create table to return
-    lua_newtable(L);
-
-    // iter
-    TAILQ_FOREACH(chan, &lua_net->net->channels, net_channels) {
-        // push index
-        lua_pushinteger(L, i);
+    // push iter func
+    lua_pushcfunction(L, lua_net_channels_iter);
 
-        // push value as new lua_chan
-        lua_chan_create(L, chan);
+    // push invariant state - the lua_net
+    lua_pushvalue(L, 1);
 
-        // store in table
-        lua_settable(L, -3);
-    }
-
-    // return table
-    return 1;
+    // return iter three-tuple
+    return 2;
 }
 
 static struct lua_method lua_net_methods[] = LUA_METHODS(
@@ -335,37 +346,49 @@
 }
 
 static struct lua_func lua_client_networks_func = LUA_FUNC(&lua_client_type, "channels",
-        "Build list of client's networks",
+        "Return an iterator over the client's networks",
 
         LUA_FUNC_ARG_END
     );
 
+static int lua_client_networks_iter (lua_State *L)
+{
+    int nargs = lua_gettop(L);
+    struct lua_client *lua_client = lua_arg_obj(L, nargs, 1, &lua_client_type, false);
+    struct lua_net *lua_net = lua_arg_obj(L, nargs, 2, &lua_net_type, true);
+    struct irc_net *net_next;
+
+    if (lua_net)
+        // return next
+        net_next = TAILQ_NEXT(lua_net->net, client_networks);
+    else
+        // return first
+        net_next = TAILQ_FIRST(&lua_client->client->networks);
+    
+    // build and return next value
+    if (net_next)
+        lua_net_create(L, net_next);
+    else
+        lua_pushnil(L);
+    
+    return 1;
+}
+
 static int lua_client_networks (lua_State *L)
 {
     struct lua_client *lua_client;
-    struct irc_net *net;
-    int i = 1;
 
     // parse args
     lua_args_parse(L, &lua_client_networks_func, (void *) &lua_client);
 
-    // create new table
-    lua_newtable(L);
-
-    // append each channel
-    TAILQ_FOREACH(net, &lua_client->client->networks, client_networks) {
-        // index
-        lua_pushinteger(L, i);
+    // push iter func
+    lua_pushcfunction(L, lua_client_networks_iter);
 
-        // push new lua_net
-        lua_net_create(L, net);
+    // push invariant state - the lua_client
+    lua_pushvalue(L, 1);
 
-        // store
-        lua_settable(L, -3);
-    }
-
-    // ok, return the table
-    return 1;
+    // return three-tuple
+    return 2;
 }
 
 static struct lua_func lua_client_quit_func = LUA_FUNC(&lua_client_type, "quit",
--- a/src/lua_type.c	Thu May 14 21:45:43 2009 +0300
+++ b/src/lua_type.c	Thu May 14 22:57:13 2009 +0300
@@ -57,6 +57,7 @@
     void *ud;
 
     // validate the userdata arg
+    // XXX: the luaL_checkudata actually raises an error itself
     if ((ud = luaL_checkudata(L, index, type->name)) == NULL) {
         luaL_error(L, "bad type argument: `%s` expected", type->name); return NULL;