为Lua封装C库:如何创建函数的嵌套表



与此问题相关的代码如下:https://github.com/jchester/lua-polarssl/tree/master/src

目前我正在尝试包装PolarSSL库的一部分(http://polarssl.org)允许我访问SHA-512 HMAC(luacrypto不提供此功能)。

我的目标API的形式是:

a_sha512_hash = polarssl.hash.sha512('text')

或更完全的

local polarssl = require 'polarssl'
local hash = polarssl.hash
a_sha512_hash = hash.sha512('test')

如果您在上面的链接中引用polarssl.c,您将看到我已经编写了包装polarssl代码的函数。然后我试着这样构建函数表:

LUA_API int luaopen_polarssl( lua_State *L ) {
  static const struct luaL_Reg core[] = {
    { NULL, NULL }
  };
  static const struct luaL_Reg hash_functions[] = {
    { "sha512", hash_sha512 },
    { "sha384", hash_sha384 },
    { NULL, NULL }
  };
  static const struct luaL_Reg hmac_functions[] = {
    { "sha512", hmac_sha512 },
    { "sha384", hmac_sha384 },
    { NULL, NULL }
  };
  luaL_register( L, CORE_MOD_NAME, core );
  luaL_register( L, HASH_MOD_NAME, hash_functions );
  luaL_register( L, HMAC_MOD_NAME, hmac_functions );
  return 1;
}

其中CORE_MOD_NAME='polarssl',HASH_MOD_NAME='polarssl.HASH',HMAC_MOD_NAME='polarssl.HMAC'.

当我运行一个类似于这个问题顶部的Lua代码的测试脚本时,我得到的是:

lua: test.lua:23: attempt to index global 'polarssl' (a nil value)
stack traceback:
    test.lua:23: in main chunk
    [C]: ?

我试着寻找如何实现这个模块的例子。submodule方法(例如naim与luaseockets),但每个人似乎都有不同的实现方式。我完全迷失了方向。

每个人似乎都有不同的实现方式。

那是Lua;每个人都按自己的方式做。这是Lua最大的优势和最大的弱点:语言提供了机制,而不是策略

您需要做的第一件事是停止使用luaL_register。是的,我知道这很方便。但你想要一些特别的东西,而luaL_register不会帮你得到它

您想要的是创建一个包含一个或多个函数的表的表。所以…就这么做吧。

创建一个表。

lua_newtable(L);

这很容易。该函数将一个表推送到堆栈上,因此堆栈上现在有一个表。这是我们将返回的表。

现在,我们需要创建一个新表来进入旧表。

lua_newtable(L);

再说一遍,很简单。接下来,我们想把我们想要进入的函数放入堆栈上的那个表中。

lua_pushcfunction(L, hash_sha512);

因此,堆栈有三样东西:目标表、"哈希"表(我们稍后将对其进行"命名"),以及我们要放入"哈希"表格中的函数。

因此,将函数放入哈希表中。

lua_setfield(L, -2, "sha512");

这将获取堆栈顶部的任何内容,并将其设置到堆栈上-2索引处的表上名为"sha512"的字段中。这就是我们的"hash"表所在的位置。此函数完成后,它将从堆栈中删除最上面的项。这会将"哈希"表留在顶部。

我们可以重复第二个函数的过程:

lua_pushcfunction(L, hash_sha384);
lua_setfield(L, -2, "sha384");

现在,我们想要将"hash"表放入我们想要返回的表中。通过另一个lua_setfield调用:,这已经足够容易了

lua_setfield(L, -2, "hash");

记住:这个函数接受堆栈顶部的。此时,我们想要返回的表(将是我们模块的表)已在堆栈上。

我们可以对"hmac"表重复此过程:

lua_newtable(L); //Create "hmac" table
lua_pushcfunction(L, hmac_sha512);
lua_setfield(L, -2, "sha512");
lua_pushcfunction(L, hmac_sha384);  
lua_setfield(L, -2, "sha384");
lua_setfield(L, -2, "hmac"); //Put the "hmac" table into our module table

模块的表中现在有两个条目:"hash"one_answers"hmac"。两者都是包含两个函数的表。

我们可以通过以下方式将其纳入全球表格:

lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, "polarssl");

并不是每个模块制造商都想这么做。有些人更喜欢强迫人们使用local polarssl = require "polarssl"语法,以避免污染全局命名空间。这取决于你。

但是,无论哪种方式,您都必须返回此表。从luaopen函数返回1,让Lua知道有一个返回值。上面的lua_pushvalue调用的唯一目的是复制表(记住:表是被引用的,所以它就像复制指针一样)。这样,当使用lua_setfield时,副本将从堆栈中删除,而原始副本仍将用作返回值。

与问题没有直接关系,但以下陈述并不完全正确:

目前我正在尝试包装PolarSSL库的一部分(http://polarssl.org)允许我访问SHA-512 HMAC(luacrypto不提供此功能)。

我不知道你指的是LuaCrypto的哪个版本,但这个LuaCrypto分叉确实提供了SHA-512 HMAC,以及OpenSSL自动支持的任何其他摘要类型。只需通过"sha512"作为摘要类型:

hmac.digest("sha512", message, key)

文档只说明了部分支持的摘要类型,可以通过调用crypto.list("digests")来检索完整的列表。

table.foreach(crypto.list("digests"), print)

仔细想想,即使是最初的LuaCrypto也应该支持SHA-512。

最新更新