lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Sat, Dec 24, 2005 at 09:35:17PM +0200, askok@dnainternet.net wrote:
> The only thing I'd really want of Lua itself, is enumerated types, so that C API
> constants can be used as type-aware parameters, and catch any "false" usage
> (color enum where font enums should be, and such). This is a major issue for
> coding larger programs with SDL, Gtk+ etc. and currently, just placing those
> enums as integers is a Lowsy Solution. I shall look into this, if it could be
> achieved by the extended metatable handling there now is, or some other "stock
> Lua" technique. 

I've found a very easy way to do this in Lua 5.0 with light userdata.
The following example, not fully tested, is similar to the code I use in
my research:

  // typedef to hold the enums
  typedef struct { const char* name; int val; } luaL_enum;

  // registers the enums in the table given at index 'tbl'
  void luaL_register_enums( lua_State* L, int tbl, const luaL_enum* enumList );
  {
    int i;
    for (i=0; enumList[i].name != NULL; ++i) {
      lua_pushstring(L, enumList[i].name);
      lua_pushlightuserdata(L, (void*) enumList+i);
      lua_rawset(L, tbl);
    }
    lua_pushlightuserdata(L, enumList);
    lua_pushnumber(L, i);
    lua_rawset(L, LUA_REGISTRYINDEX);
  }

  int luaL_toenum( lua_State* L, int enumIdx, const luaL_enum* enumList )
  {
    const luaL_enum* ep;
    int ei, maxent;

    lua_pushlightuserdata(L, enumList);
    lua_rawget(L, LUA_REGISTRYINDEX);
    if (!lua_isnumber(L,-1)) { 
      lua_pop(L,1); return 0; 
    }
    maxent = lua_tonumber(L,-1);
    lua_pop(L,1);

    if (!lua_islightuserdata(L,enumIdx)) return 0;
    ep = (luaL_enum*) lua_touserdata(L,enumIdx);
    ei = enumList - ep;
    if (ei < 0 || ei >= maxent) return 0;
    return enumList[ei].val;
  }

  int luaL_isenum( lua_State* L, int enumIdx, const luaL_enum* enumList )
  {
    const luaL_enum* ep;
    int ei, maxent;

    lua_pushlightuserdata(L, enumList);
    lua_rawget(L, LUA_REGISTRYINDEX);
    if (!lua_isnumber(L,-1)) { 
      lua_pop(L,1); return 0; 
    }
    maxent = lua_tonumber(L,-1);
    lua_pop(L,1);

    if (!lua_islightuserdata(L,enumIdx)) return 0;
    ep = (luaL_enum*) lua_touserdata(L,enumIdx);
    ei = enumList - ep;
    return (ei >= 0 && ei < maxent);
  }

  //
  //// EXAMPLE OF ABOVE
  //
  // example enums
  enum LibEnum { LIB_FOO = 1, LIB_BAR };

  // enums for our library
  static const luaL_enum library_enums[] = {
    { "FOO", (int) LIB_FOO },
    { "BAR", (int) LIB_BAR },
    { 0 },
  };

  int lib_enumToString( lua_State* L )
  {
    int v;
    LibEnum e;
    v = luaL_toenum(L,1);
    if (v==0 && !luaL_isenum(L,1)) luaL_typerror(L,1,"LibEnum");
    e = (LibEnum) v;
    switch(e) {
      case LIB_FOO: lua_pushstring(L, "FOO"); break;
      case LIB_BAR: lua_pushstring(L, "BAR"); break;
      default:      lua_pushstring(L, "UNKNOWN"); break;
    }
    return 1;
  }

  static const struct luaL_reg lib_fxns[] = {
    { "enumToString", lib_enumToString },
    { 0 },
  };

  int luaopen_lib(lua_State* L)
  {
    luaL_openlib(L, "lib", lib_fxns);
    luaL_register_enums(L, lua_gettop(L), library_enums);
    return 0;
  }

Cheers!

-- 
Shannon Stewman         | Let us walk through the waning night,
Caught in a whirlpool,  | As dawn-rays tickle our toes, the dew soothes
A quartering act:       | Our blistered soles, and damp bones stir
Solitude or society?    | As crimson cracks under the blue-grey sky.


-- 
Shannon Stewman         | Let us walk through the waning night,
Caught in a whirlpool,  | As dawn-rays tickle our toes, the dew soothes
A quartering act:       | Our blistered soles, and damp bones stir
Solitude or society?    | As crimson cracks under the blue-grey sky.