使用元表和闭包进行绑定 |
|
以下是如何使用包含元表的闭包将 Lua 绑定到 Thomas Boutell 的 GD 图形库[1] 的示例。在 Tom 的网页上可以找到如何在 C 中使用 GD 的原始示例[2]。
Image.new 是一个构造函数,它返回一个包含要操作的图像的用户数据。用户数据的元表有一个垃圾回收事件来销毁图像,以及一个索引事件来调用绘制图像和将图像保存到文件所需的函数。只实现了三个函数:ColorAllocate、Line 和 PNG。
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "gd.h"
/*
==============================================================================
Example Lua bindings for GD
==============================================================================
*/
#define IMAGE "Image"
static gdImagePtr checkimage (lua_State *L, int index)
{
luaL_checktype(L, index, LUA_TUSERDATA);
lua_getmetatable(L, index);
if( ! lua_equal(L, lua_upvalueindex(1), -1) )
luaL_typerror(L, index, IMAGE); /* die */
lua_pop(L, 1);
return (gdImagePtr)lua_unboxpointer(L, index);
}
static gdImagePtr pushimage (lua_State *L, gdImagePtr im)
{
lua_boxpointer(L, im);
lua_pushvalue(L, lua_upvalueindex(1));
lua_setmetatable(L, -2);
return im;
}
static int image_new (lua_State *L)
{
int x = luaL_checkint(L, 1);
int y = luaL_checkint(L, 2);
pushimage(L, gdImageCreate(x, y));
return 1;
}
static int image_destroy (lua_State *L)
{
gdImagePtr im = (gdImagePtr)lua_unboxpointer(L, 1);
if (im) gdImageDestroy(im);
return 0;
}
static int image_color_allocate (lua_State *L)
{
gdImagePtr im = checkimage(L, 1);
int r = luaL_checkint(L, 2);
int g = luaL_checkint(L, 3);
int b = luaL_checkint(L, 4);
lua_pushnumber(L, gdImageColorAllocate(im, r, g, b));
return 1;
}
static int image_line (lua_State *L)
{
gdImagePtr im = checkimage(L, 1);
int x1 = luaL_checkint(L, 2);
int y1 = luaL_checkint(L, 3);
int x2 = luaL_checkint(L, 4);
int y2 = luaL_checkint(L, 5);
int colour = luaL_checkint(L, 6);
gdImageLine(im, x1, y1, x2, y2, colour);
return 0;
}
static int image_png (lua_State *L)
{
/* Output the image to the disk file in PNG format. */
gdImagePtr im = checkimage(L, 1);
const char *name = luaL_checkstring(L, 2);
FILE *pngout = fopen( name, "wb");
gdImagePng(im, pngout);
fclose(pngout);
return 0;
}
static const luaL_reg meta_methods[] = {
{"__gc", image_destroy },
{0,0}
};
static const luaL_reg image_methods[] = {
{"new", image_new},
{"colorallocate", image_color_allocate},
{"line", image_line},
{"PNG", image_png},
{0,0}
};
#define newtable(L) (lua_newtable(L), lua_gettop(L))
int Image_register (lua_State *L)
{
int metatable, methods;
lua_pushliteral(L, IMAGE); /* name of Image table */
methods = newtable(L); /* Image methods table */
metatable = newtable(L); /* Image metatable */
lua_pushliteral(L, "__index"); /* add index event to metatable */
lua_pushvalue(L, methods);
lua_settable(L, metatable); /* metatable.__index = methods */
lua_pushliteral(L, "__metatable"); /* hide metatable */
lua_pushvalue(L, methods);
lua_settable(L, metatable); /* metatable.__metatable = methods */
luaL_openlib(L, 0, meta_methods, 0); /* fill metatable */
luaL_openlib(L, 0, image_methods, 1); /* fill Image methods table */
lua_settable(L, LUA_GLOBALSINDEX); /* add Image to globals */
return 0;
}
int main(int argc, char *argv[])
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
luaopen_debug(L);
Image_register(L);
if(argc>1) lua_dofile(L, argv[1]);
lua_close(L);
return 0;
}
此代码可以为 Lua 5.0 编译如下
gcc gd.c -L/usr/local/lib/ -llua -llualib -lgd -lpng
for n,v in pairs(Image) do print(n,v) end size = 256 im = Image.new(size, size) print(im) white = im:colorallocate(255, 255, 255) for i = 0,size-1,1 do c = im:colorallocate(0, i, i) im:line(0, 0, size-1 , i, c) end im:PNG'test.png' -- debug.debug()
$ ./a gd.lua line function: 0x100553b8 PNG function: 0x10055500 colorallocate function: 0x10055418 new function: 0x10054ff8 userdata: 0x10055e98
这是测试代码创建的图像。
下一个示例展示了如何使用索引和新索引事件来读取和写入结构成员BindingWithMembersAndMethods