The Battle for Wesnoth  1.19.5+dev
lua_attributes.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /// Attribute registration system, mainly for objects with a lot of attributes, like units
16 /// Not used for GUI2 widgets, as they're even more complicated with a deep hierarchy.
17 
18 #pragma once
19 
20 struct lua_State;
21 class t_string;
22 class vconfig;
23 
24 #include "config.hpp"
25 #include "map/location.hpp"
26 #include "variable_info.hpp"
27 
28 #include <string>
29 #include <string_view>
30 #include <vector>
31 
32 template<typename T>
33 std::decay_t<T> lua_check(lua_State *L, int n);
34 
35 /// Holds a lookup table for members of one type of object.
36 struct luaW_Registry {
37  inline static std::map<std::string_view /* metatable */, std::reference_wrapper<luaW_Registry>> lookup;
38  using getters_list = std::map<std::string /* attribute */, std::function<bool(lua_State* L,bool nop)>>;
39  /// A map of callbacks that read data from the object.
41  using setters_list = std::map<std::string, std::function<bool(lua_State* L,int idx,bool nop)>>;
42  /// A map of callbacks that write data to the object.
44  using validators_list = std::map<std::string, std::function<bool(lua_State* L)>>;
45  /// A map of callbacks that check if a member is available.
47  /// The internal metatable string for the object (from __metatable)
48  std::string private_metatable;
49  /// Optional external metatable for the object (eg "wesnoth", "units")
50  /// All entries of this table will be treated as members of the object.
51  std::vector<std::string> public_metatable;
52  luaW_Registry() = delete;
53  luaW_Registry(const std::initializer_list<std::string>& mt);
55  /// Implement __index metamethod
56  int get(lua_State* L);
57  /// Implement __newindex metamethod
58  int set(lua_State* L);
59  /// Implement __dir metamethod
60  int dir(lua_State* L);
61 };
62 
64 
65 template<typename object_type, typename value_type>
66 struct lua_getter
67 {
68  virtual value_type get(lua_State* L, const object_type& obj) const = 0;
69  virtual ~lua_getter() = default;
70 };
71 
72 template<typename object_type, typename value_type>
73 struct lua_setter
74 {
75  virtual void set(lua_State* L, object_type& obj, const value_type& value) const = 0;
76  virtual ~lua_setter() = default;
77 };
78 
79 template<typename object_type>
81 {
82  virtual bool is_active(lua_State* L, const object_type& obj) const = 0;
83  virtual ~lua_validator() = default;
84 };
85 
86 template<typename T> struct lua_object_traits;
87 
88 template<typename object_type, typename value_type, typename action_type, lua_attrfunc_type type>
89 void register_lua_attribute(const char* name)
90 {
91  using obj_traits = lua_object_traits<object_type>;
92  using map_type = std::conditional_t<type == lua_attrfunc_type::validator, luaW_Registry::validators_list, std::conditional_t<type == lua_attrfunc_type::setter, luaW_Registry::setters_list, luaW_Registry::getters_list>>;
93  using callback_type = typename map_type::mapped_type;
94  map_type* map;
95  callback_type fcn;
96  if constexpr(type == lua_attrfunc_type::setter) {
97  map = &luaW_Registry::lookup.at(obj_traits::metatable).get().setters;
98  fcn = [action = action_type()](lua_State* L, int idx, bool nop) {
99  if(nop) return true;
100  decltype(auto) obj = obj_traits::get(L, 1);
101  action.set(L, obj, lua_check<value_type>(L, idx));
102  return true;
103  };
104  } else if constexpr(type == lua_attrfunc_type::getter) {
105  map = &luaW_Registry::lookup.at(obj_traits::metatable).get().getters;
106  fcn = [action = action_type()](lua_State* L, bool nop) {
107  if(nop) return true;
108  lua_push(L, action.get(L, obj_traits::get(L, 1)));
109  return true;
110  };
111  } else if constexpr(type == lua_attrfunc_type::validator) {
112  map = &luaW_Registry::lookup.at(obj_traits::metatable).get().validators;
113  fcn = [action = action_type()](lua_State* L) {
114  return action.is_active(L, obj_traits::get(L, 1));
115  };
116  }
117  (*map)[std::string(name)] = fcn;
118 }
119 
120 #define LATTR_MAKE_UNIQUE_ID(base, id, obj_name) BOOST_PP_CAT(BOOST_PP_CAT(base, id), BOOST_PP_CAT(_for_, obj_name))
121 
122 #define LATTR_GETTER5(name, value_type, obj_type, obj_name, id) \
123 struct LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name) : public lua_getter<obj_type, value_type> { \
124  using object_type = obj_type; \
125  virtual value_type get(lua_State* L, const object_type& obj_name) const override; \
126 }; \
127 struct LATTR_MAKE_UNIQUE_ID(getter_adder_, id, obj_name) { \
128  LATTR_MAKE_UNIQUE_ID(getter_adder_, id, obj_name) () \
129  { \
130  register_lua_attribute<obj_type, value_type, LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name), lua_attrfunc_type::getter>(name); \
131  } \
132 }; \
133 static LATTR_MAKE_UNIQUE_ID(getter_adder_, id, obj_name) LATTR_MAKE_UNIQUE_ID(getter_adder_instance_, id, obj_name) ; \
134 value_type LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name)::get([[maybe_unused]] lua_State* L, const LATTR_MAKE_UNIQUE_ID(getter_, id, obj_name)::object_type& obj_name) const
135 
136 
137 #define LATTR_SETTER5(name, value_type, obj_type, obj_name, id) \
138 struct LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name) : public lua_setter<obj_type, value_type> { \
139  using object_type = obj_type; \
140  void set(lua_State* L, object_type& obj_name, const value_type& value) const override; \
141 }; \
142 struct LATTR_MAKE_UNIQUE_ID(setter_adder_, id, obj_name) { \
143  LATTR_MAKE_UNIQUE_ID(setter_adder_, id, obj_name) ()\
144  { \
145  register_lua_attribute<obj_type, value_type, LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name), lua_attrfunc_type::setter>(name); \
146  } \
147 }; \
148 static LATTR_MAKE_UNIQUE_ID(setter_adder_, id, obj_name) LATTR_MAKE_UNIQUE_ID(setter_adder_instance_, id, obj_name); \
149 void LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name)::set([[maybe_unused]] lua_State* L, LATTR_MAKE_UNIQUE_ID(setter_, id, obj_name)::object_type& obj_name, const value_type& value) const
150 
151 
152 #define LATTR_VALID5(name, obj_type, obj_name, id) \
153 struct LATTR_MAKE_UNIQUE_ID(check_, id, obj_name) : public lua_validator<obj_type> { \
154  using object_type = obj_type; \
155  bool is_active(lua_State* L, const object_type& obj_name) const override; \
156 }; \
157 struct LATTR_MAKE_UNIQUE_ID(check_adder_, id, obj_name) { \
158  LATTR_MAKE_UNIQUE_ID(check_adder_, id, obj_name) ()\
159  { \
160  register_lua_attribute<obj_type, void, LATTR_MAKE_UNIQUE_ID(check_, id, obj_name), lua_attrfunc_type::validator>(name); \
161  } \
162 }; \
163 static LATTR_MAKE_UNIQUE_ID(check_adder_, id, obj_name) LATTR_MAKE_UNIQUE_ID(check_adder_instance_, id, obj_name); \
164 bool LATTR_MAKE_UNIQUE_ID(check_, id, obj_name)::is_active([[maybe_unused]] lua_State* L, const LATTR_MAKE_UNIQUE_ID(check_, id, obj_name)::object_type& obj_name) const
165 
166 
167 /**
168  * @param name: string attribute name
169  * @param value_type: the type of the attribute, for example int or std::string
170  * @param obj_type: the type of the object, for example lua_unit
171  * @param obj_name: a name for the variable that will hold the object
172  */
173 #define LATTR_GETTER(name, value_type, obj_type, obj_name) LATTR_GETTER5(name, value_type, obj_type, obj_name, __LINE__)
174 
175 #define LATTR_SETTER(name, value_type, obj_type, obj_name) LATTR_SETTER5(name, value_type, obj_type, obj_name, __LINE__)
176 
177 #define LATTR_VALID(name, obj_type, obj_name) LATTR_VALID5(name, obj_type, obj_name, __LINE__)
A variable-expanding proxy for the config class.
Definition: variable.hpp:45
Definitions for the interface to Wesnoth Markup Language (WML).
std::decay_t< T > lua_check(lua_State *L, int n)
Definition: push_check.hpp:411
lua_attrfunc_type
void register_lua_attribute(const char *name)
CURSOR_TYPE get()
Definition: cursor.cpp:216
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
getters_list getters
A map of callbacks that read data from the object.
setters_list setters
A map of callbacks that write data to the object.
std::map< std::string, std::function< bool(lua_State *L)> > validators_list
validators_list validators
A map of callbacks that check if a member is available.
static std::map< std::string_view, std::reference_wrapper< luaW_Registry > > lookup
std::string private_metatable
The internal metatable string for the object (from __metatable)
std::map< std::string, std::function< bool(lua_State *L, int idx, bool nop)> > setters_list
std::vector< std::string > public_metatable
Optional external metatable for the object (eg "wesnoth", "units") All entries of this table will be ...
luaW_Registry()=delete
int set(lua_State *L)
Implement __newindex metamethod.
int get(lua_State *L)
Implement __index metamethod.
std::map< std::string, std::function< bool(lua_State *L, bool nop)> > getters_list
virtual value_type get(lua_State *L, const object_type &obj) const =0
virtual ~lua_getter()=default
virtual void set(lua_State *L, object_type &obj, const value_type &value) const =0
virtual ~lua_setter()=default
virtual bool is_active(lua_State *L, const object_type &obj) const =0
virtual ~lua_validator()=default
static map_location::direction n