Question

I used lualite to wrap the following object in lua:

class SpriteComponent : public Component
{
public:
    SpriteComponent();

    std::string name() const;
    std::string textureId() const;
    void setTextureId(const std::string& id);
    int spriteCoordX() const;
    void setSpriteCoordX(int value);
    int spriteCoordY() const;
    void setSpriteCoordY(int value);
};

The binding code:

module(L,
    class_<SpriteComponent>("SpriteComponent")
        .constructor("new")
        .def("name", &SpriteComponent::name)
        .property("textureId", 
            &SpriteComponent::textureId, &SpriteComponent::setTextureId)
        .property("spriteCoordX", 
            &SpriteComponent::spriteCoordX, &SpriteComponent::setSpriteCoordX)
        .property("spriteCoordY", 
            &SpriteComponent::spriteCoordY, &SpriteComponent::setSpriteCoordY)
);

Is there a way (either on the lua side or the C++ side) to get a list of properties? If I list the pairs in the resulting table, I only get name and __instance.

local o = SpriteComponent.new()
for key,value in pairs(o) do
    print("found member " .. key);
end

I even tried some of these table printers, but no luck.

Était-ce utile?

La solution

I'm the author of lualite. I wrote the library to be minimalist and fast and did not foresee the need for reflection :) Anyway, what you are looking for can be found as 2 static members:

static ::std::unordered_map<char const*, detail::map_member_info_type,
  detail::unordered_hash, detail::unordered_eq> getters_;
static ::std::unordered_map<char const*, detail::map_member_info_type,
  detail::unordered_hash, detail::unordered_eq> setters_;

the char const* is the name of the property, the value being a map_member_info_type, which are essentially two pointers, one to a lualite stub, the other to the C++ member function.

struct map_member_info_type
{
  lua_CFunction callback;

  member_func_type func;
};

If you like, I can make both members public. The way properties work is as follows:

A default getter is (usually) set in the wrapped class's instance table:

lua_pushcclosure(L, default_getter<C>, 2);

rawsetfield(L, -2, "__index");

This points to the default getter:

template <class C>
int default_getter(lua_State* const L)
{
  assert(2 == lua_gettop(L));
  auto const i(lualite::class_<C>::getters_.find(lua_tostring(L, 2)));

  return lualite::class_<C>::getters_.end() == i
    ? 0
    : (lua_pushlightuserdata(L, &i->second.func),
      lua_replace(L, lua_upvalueindex(2)),
      (i->second.callback)(L));
}

which looks for the name of the property (which is on the stack). That could be anything really and if it does not find the name, it returns 0, otherwise, it forwards the call to the lualite stub made for the member function, which then handles the arguments and the return value(s).

Autres conseils

If you could tolerate having to list the property names in your Lua code, this could be a solution:

local GetPropertyList
do -- to make `property_names` "private" to GetPropertyList
    property_names = {
        ["SpriteComponent"] = { "textureId", "spriteCoordX", "spriteCoordY" },
        -- property names for other components, e.g.
        ["AnotherComponentName"] = { "propName1", "propName2" },
    }
    function GetPropertyList( object )  --[[local]]
        local component_name = object:name()
        local prop_names = property_names[component_name]
        if not prop_names then
            error( "unsupported component" )
        end
        local res = {}
        for _, p_name in ipairs( prop_names ) do
            local p_val = object[p_name]
            res[ #res + 1 ] = p_val
            -- or use this if you want a key-value map:
            -- res[p_name] = p_val
        end
        return res
    end  -- function
end  -- do


for k, v in pairs( GetPropertyList(o) ) do
    print( k, v )
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top