有没有一种方法可以可靠地区分 cdata 和 ctypes?

问题描述

我是一个需要区别对待 cdata 和 ctypes 的库的作者。目前,我使用 ffi.typeof(value) == value,但这会导致某些带有定义 __eq 的元表的 cdata 出错。提交此错误报告的用户建议改为检查 tostring(value):match"^ctype",但这只是将问题转移到带有定义 __tostring 的元表的 cdata。我已经尝试过 rawequal,但我的原始条件首先依赖于元魔法,因此根本不起作用。

我正在考虑使用 local success,eq = pcall(function() return ffi.typeof(value) == value end) 并使用条件 success and eq,但我想知道:有没有更可靠、更少黑客的方法来实现这一目标?

解决方法

下面的解决方案也是 hack-y,但您可能会感兴趣。
它滥用了 tonumber() 适用于 ctypes 的未记录功能。

local function is_ctype(x)
   return type(x) == "cdata"
      and tonumber(x) ~= nil
      and tostring(x):sub(1,5) == "ctype"
end

请注意,tostring() 仅适用于可转换为数字的 cdata。
ctype<complex> 是唯一一种其值可转换为数字的元类型 ctype。
令人高兴的是,ctype<complex> 不尊重 __tostring 元方法。 :-)

,

这也困扰了我一段时间,这是我目前得到的。

代码适用于我的用例,但它不处理这种边缘情况:


assert(ffi.new("int",9) == ffi.typeof("int")) --> this assertion is true.

我找不到解决这个问题的方法,我认为这就是 LuaJIT 的工作方式。 所有其他基本类型也发生同样的情况(带有各自的 ID)

完整代码:


local ffi = require "ffi"

function isctype(o)
    -- ctypes can be converted to a number
    local check = tonumber(o)
    if check == nil then
        return false
    end

    -- typeinfo expects a number,we have a number
    local maybeInfo = ffi.typeinfo(check)
    local sureInfo = ffi.typeinfo(ffi.typeof(o))

    -- type infos differ
    if maybeInfo.info ~= sureInfo.info then
        return false
    end

    local type = ffi.typeof(o)

    -- No way around this except calling tostring(o)
    -- which would have it's own drawbacks.

    -- When we got here we have the special case
    -- that the type-id is equal to the result
    -- of tonumber(o).
    -- this happens e.g. for typeof"int" and 9.
    -- In this case the result is also true,-- which is actually not quite what I'd expect.

    return o == type
end

local ct = ffi.typeof("struct { int x; }")

print("type",isctype(ct)) --> true
print("data",isctype(ffi.new(ct))) --> false
print("type",isctype(ffi.typeof("int"))) --> true
print("type",isctype(ffi.typeof("const char*"))) --> true
print("data",isctype(ffi.new("float",3))) --> false
print("data",isctype(ffi.new("int",isctype(ffi.new("intptr_t",isctype(ffi.new("int[1]",isctype(ffi.new("const char*","yo"))) --> false
print("data",8))) --> false

-- this is sad :(
print("data",9))) --> true

assert(ffi.new("int",9) == ffi.typeof("int"))

print("assertion did not fail :(")