Skip to content

Commit 2dfff99

Browse files
authored
Merge pull request #631 from Olivine-Labs/luajit/metatype
fix(luajit) add 'metatype' as a patched method
2 parents 62205ac + 1cd05b2 commit 2dfff99

4 files changed

Lines changed: 115 additions & 32 deletions

File tree

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package = 'busted'
2-
version = 'scm-1'
2+
version = 'scm-2'
33
source = {
44
url = "git://github.com/Olivine-Labs/busted",
55
branch = "master"
@@ -45,6 +45,7 @@ build = {
4545
['busted.block'] = 'busted/block.lua',
4646
['busted.execute'] = 'busted/execute.lua',
4747
['busted.init'] = 'busted/init.lua',
48+
['busted.luajit'] = 'busted/luajit.lua',
4849

4950
['busted.modules.configuration_loader'] = 'busted/modules/configuration_loader.lua',
5051
['busted.modules.luacov'] = 'busted/modules/luacov.lua',

busted/luajit.lua

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
local isJit = (tostring(assert):match('builtin') ~= nil)
2+
3+
if not isJit then
4+
return function() end
5+
end
6+
7+
-- pre-load the ffi module, such that it becomes part of the environment
8+
-- and Busted will not try to GC and reload it. The ffi is not suited
9+
-- for that and will occasionally segfault if done so.
10+
local ffi = require "ffi"
11+
12+
13+
-- patching assumes;
14+
-- * first parameter to be a unique key to identify repeated calls
15+
-- * only a single return value
16+
17+
local function patch_with_return_value(func_name)
18+
local original = ffi[func_name]
19+
local original_store = {}
20+
21+
ffi[func_name] = function (primary, ...)
22+
if original_store[primary] then
23+
return original_store[primary]
24+
end
25+
local success, result, err = pcall(original, primary, ...)
26+
if not success then
27+
-- hard error was thrown
28+
error(result, 2)
29+
end
30+
if not result then
31+
-- soft error was returned
32+
return result, err
33+
end
34+
-- it worked, store and return
35+
original_store[primary] = result
36+
return result
37+
end
38+
end
39+
40+
local function patch_without_return_value(func_name)
41+
local original = ffi[func_name]
42+
local original_store = {}
43+
44+
ffi[func_name] = function (primary, ...)
45+
if original_store[primary] then
46+
return
47+
end
48+
local success, result = pcall(original, primary, ...)
49+
if not success then
50+
-- hard error was thrown
51+
error(result, 2)
52+
end
53+
-- store and return
54+
original_store[primary] = true
55+
return result
56+
end
57+
end
58+
59+
return function()
60+
patch_without_return_value("cdef")
61+
patch_with_return_value("typeof")
62+
patch_with_return_value("metatype")
63+
end

busted/runner.lua

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -138,37 +138,7 @@ return function(options)
138138
})
139139

140140
-- Pre-load the LuaJIT 'ffi' module if applicable
141-
local isJit = (tostring(assert):match('builtin') ~= nil)
142-
if isJit then
143-
-- pre-load the ffi module, such that it becomes part of the environment
144-
-- and Busted will not try to GC and reload it. The ffi is not suited
145-
-- for that and will occasionally segfault if done so.
146-
local ffi = require "ffi"
147-
148-
-- Now patch ffi.cdef to only be called once with each definition, as it
149-
-- will error on re-registering.
150-
local old_cdef = ffi.cdef
151-
local exists = {}
152-
ffi.cdef = function(def)
153-
if exists[def] then return end
154-
exists[def] = true
155-
return old_cdef(def)
156-
end
157-
158-
-- Now patch ffi.typeof to only be called once with each definition, as it
159-
-- will error on re-registering.
160-
local old_typeof = ffi.typeof
161-
local exists_typeof = {}
162-
ffi.typeof = function(def)
163-
if exists_typeof[def] then return exists_typeof[def] end
164-
local ok, err = old_typeof(def)
165-
if ok then
166-
exists_typeof[def] = ok
167-
return ok
168-
end
169-
return ok, err
170-
end
171-
end
141+
require 'busted.luajit'()
172142

173143
-- Set up helper script
174144
if cliArgs.helper and cliArgs.helper ~= '' then

spec/luajit_spec.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
local isJit = (tostring(getmetatable):match('builtin') ~= nil)
2+
3+
local it = it
4+
if not isJit then
5+
it = pending
6+
end
7+
8+
describe("LuaJIT FFI patching:", function()
9+
10+
local _, ffi = pcall(require, "ffi")
11+
12+
it("ffi.cdef", function()
13+
local def =[[
14+
typedef struct foo { int a, b; } foo_t; // Declare a struct and typedef.
15+
int dofoo(foo_t *f, int n); /* Declare an external C function. */
16+
]]
17+
18+
ffi.cdef(def)
19+
assert.has.no.error(function()
20+
ffi.cdef(def)
21+
end)
22+
end)
23+
24+
it("ffi.typeof", function()
25+
local ct = "struct { int top, max; }"
26+
27+
ffi.typeof(ct)
28+
assert.has.no.error(function()
29+
ffi.typeof(ct)
30+
end)
31+
end)
32+
33+
it("ffi.metatype", function()
34+
local name = "brinevector"
35+
local mt = {}
36+
ffi.cdef([[
37+
typedef struct {
38+
double x;
39+
double y;
40+
} ]] .. name .. [[;
41+
]])
42+
43+
ffi.metatype(name, mt)
44+
assert.has.no.error(function()
45+
ffi.metatype(name, mt)
46+
end)
47+
end)
48+
49+
end)

0 commit comments

Comments
 (0)