使用指针的用户数据示例

lua-users home
wiki

描述

如果您想要从 Lua 中操作的结构需要由 C/C++ 代码分配或创建,那么最好将指向该结构的指针存储在用户数据中。

例如,在使用 Thomas Boutell 的 GD 图形库[1]创建图像时,函数 gdImageCreate 只返回指向图像对象的指针。

Image.new 是一个构造函数,它返回一个包含指向要操作的图像的指针的用户数据。用户数据的元表有一个垃圾回收事件来销毁图像,以及一个索引事件来调用图像方法。

只实现了三种方法

用户数据的元表被放在注册表中,__index 字段指向方法表,以便 object:method() 语法可以正常工作。方法表存储在全局表中,以便脚本可以添加用 Lua 编写的其他方法。

操作 Image 的 Lua 函数需要访问堆栈上的用户数据,或者将新的用户数据压入堆栈。

checkImage 确保堆栈上的用户数据是正确的类型,并返回用户数据中的 Image 指针。

pushImage 将新的用户数据留在堆栈顶部,设置其元表,并在用户数据中设置 Image 指针。

C 代码

#include <stdio.h>

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "gd.h"

/*
==============================================================================
  Example Lua bindings for GD
==============================================================================
*/


#define IMAGE "Image"

typedef gdImagePtr Image;


static Image toImage (lua_State *L, int index)
{
  Image *pi = (Image *)lua_touserdata(L, index);
  if (pi == NULL) luaL_typerror(L, index, IMAGE);
  return *pi;
}

static Image checkImage (lua_State *L, int index)
{
  Image *pi, im;
  luaL_checktype(L, index, LUA_TUSERDATA);
  pi = (Image*)luaL_checkudata(L, index, IMAGE);
  if (pi == NULL) luaL_typerror(L, index, IMAGE);
  im = *pi;
  if (!im)
    luaL_error(L, "null Image");
  return im;
}

static Image *pushImage (lua_State *L, Image im)
{
  Image *pi = (Image *)lua_newuserdata(L, sizeof(Image));
  *pi = im;
  luaL_getmetatable(L, IMAGE);
  lua_setmetatable(L, -2);
  return pi;
}


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_color_allocate (lua_State *L)
{
  Image 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)
{
  Image 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. */
  Image 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 Image_methods[] = {
  {"new",           Image_new},
  {"colorallocate", Image_color_allocate},
  {"line",          Image_line},
  {"PNG",           Image_png},
  {0,0}
};


static int Image_gc (lua_State *L)
{
  Image im = toImage(L, 1);
  if (im) gdImageDestroy(im);
  printf("goodbye Image (%p)\n", lua_touserdata(L, 1));
  return 0;
}

static int Image_tostring (lua_State *L)
{
  lua_pushfstring(L, "Image: %p", lua_touserdata(L, 1));
  return 1;
}

static const luaL_reg Image_meta[] = {
  {"__gc",       Image_gc},
  {"__tostring", Image_tostring},
  {0, 0}
};


int Image_register (lua_State *L)
{
  luaL_openlib(L, IMAGE, Image_methods, 0);  /* create methods table,
                                                add it to the globals */
  luaL_newmetatable(L, IMAGE);        /* create metatable for Image,
                                         add it to the Lua registry */
  luaL_openlib(L, 0, Image_meta, 0);  /* fill metatable */
  lua_pushliteral(L, "__index");
  lua_pushvalue(L, -3);               /* dup methods table*/
  lua_rawset(L, -3);                  /* metatable.__index = methods */
  lua_pushliteral(L, "__metatable");
  lua_pushvalue(L, -3);               /* dup methods table*/
  lua_rawset(L, -3);                  /* hide metatable:
                                         metatable.__metatable = methods */
  lua_pop(L, 1);                      /* drop metatable */
  return 1;                           /* return methods on the stack */
}


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

Lua 测试代码

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: 0x10054ff0
PNG     function: 0x100553b8
colorallocate   function: 0x100552f8
new     function: 0x10054fb8
Image (0x10055ef0)
goodbye Image (0x10055ef0)

这是测试代码创建的图像。

相关页面


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2007 年 1 月 6 日下午 7:31 GMT (差异)