Initial revision
[luabind.git] / luabind / functor.hpp
blobcf6e761116386b67cd43a5f44c397ba5658c666a
1 // Copyright (c) 2003 Daniel Wallin and Arvid Norberg
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
23 #if !BOOST_PP_IS_ITERATING
25 #ifndef LUABIND_FUNCTOR_HPP_INCLUDED
26 #define LUABIND_FUNCTOR_HPP_INCLUDED
28 #include <boost/preprocessor/repeat.hpp>
29 #include <boost/preprocessor/repetition/enum_params.hpp>
30 #include <boost/preprocessor/repetition/enum_params.hpp>
31 #include <boost/preprocessor/iteration/iterate.hpp>
32 #include <boost/type_traits/is_void.hpp>
33 #include <boost/mpl/if.hpp>
35 #include <luabind/config.hpp>
36 #include <luabind/detail/policy.hpp>
37 #include <luabind/detail/convert_to_lua.hpp>
38 #include <luabind/detail/error.hpp>
40 namespace luabind
42 //template<class Ret>
43 //class functor;
45 namespace detail
48 struct functor_from;
51 // if the proxy_functor_caller returns non-void
52 template<class Ret, class Tuple>
53 class proxy_functor_caller
55 // template<class T> friend class luabind::functor;
56 public:
58 proxy_functor_caller(luabind::functor<Ret>* o, const Tuple args)
59 : m_func(o)
60 , m_args(args)
61 , m_called(false)
65 proxy_functor_caller(const proxy_functor_caller& rhs)
66 : m_func(rhs.m_func)
67 , m_args(rhs.m_args)
68 , m_called(rhs.m_called)
70 rhs.m_called = true;
73 ~proxy_functor_caller()
75 if (m_called) return;
77 m_called = true;
78 lua_State* L = m_func->lua_state();
80 // get the function
81 m_func->pushvalue();
83 push_args_from_tuple<1>::apply(L, m_args);
84 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
86 #ifndef LUABIND_NO_EXCEPTIONS
87 throw luabind::error();
88 #else
89 assert(0);
90 #endif
94 operator Ret()
96 typename default_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
98 m_called = true;
99 lua_State* L = m_func->lua_state();
100 detail::stack_pop p(L, 1); // pop the return value
102 // get the function
103 m_func->pushvalue();
105 push_args_from_tuple<1>::apply(L, m_args);
106 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
108 #ifndef LUABIND_NO_EXCEPTIONS
109 throw luabind::error();
110 #else
111 assert(0);
112 #endif
115 #ifndef LUABIND_NO_ERROR_CHECKING
116 #ifndef LUABIND_NO_EXCEPTIONS
118 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
120 throw cant_convert_return_value();
122 #else
123 assert(converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) >= 0);
124 #endif
125 #endif
126 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
129 template<class Policies>
130 Ret operator[](const Policies& p)
132 typedef typename detail::find_conversion_policy<0, Policies>::type converter_policy;
133 typename converter_policy::template generate_converter<Ret, lua_to_cpp>::type converter;
135 m_called = true;
136 lua_State* L = m_func->lua_state();
137 detail::stack_pop popper(L, 1); // pop the return value
139 // get the function
140 m_func->pushvalue();
142 detail::push_args_from_tuple<1>::apply(L, m_args, p);
143 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
145 #ifndef LUABIND_NO_EXCEPTIONS
146 throw error();
147 #else
148 assert(0);
149 #endif
152 #ifndef LUABIND_NO_ERROR_CHECKING
153 #ifndef LUABIND_NO_EXCEPTIONS
155 if (converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) < 0)
157 throw cant_convert_return_value();
159 #else
160 assert(converter.match(L, LUABIND_DECORATE_TYPE(Ret), -1) >= 0);
161 #endif
162 #endif
163 return converter.apply(L, LUABIND_DECORATE_TYPE(Ret), -1);
166 private:
168 luabind::functor<Ret>* m_func;
169 Tuple m_args;
170 mutable bool m_called;
174 // if the proxy_member_caller returns void
175 template<class Tuple>
176 class proxy_functor_void_caller
178 // template<class T> friend class luabind::functor;
179 public:
181 proxy_functor_void_caller(luabind::functor<void>* o, const Tuple args)
182 : m_func(o)
183 , m_args(args)
184 , m_called(false)
188 proxy_functor_void_caller(const proxy_functor_void_caller& rhs)
189 : m_func(rhs.m_func)
190 , m_args(rhs.m_args)
191 , m_called(rhs.m_called)
193 rhs.m_called = true;
196 ~proxy_functor_void_caller()
198 if (m_called) return;
200 m_called = true;
201 lua_State* L = m_func->lua_state();
203 // get the function
204 m_func->pushvalue();
206 push_args_from_tuple<1>::apply(L, m_args);
207 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
209 #ifndef LUABIND_NO_EXCEPTIONS
210 throw luabind::error();
211 #else
212 assert(0);
213 #endif
217 template<class Policies>
218 void operator[](const Policies& p)
220 m_called = true;
221 lua_State* L = m_func->lua_state();
223 // get the function
224 m_func->pushvalue();
226 detail::push_args_from_tuple<1>::apply(L, m_args, p);
227 if (lua_pcall(L, boost::tuples::length<Tuple>::value, 0, 0))
229 #ifndef LUABIND_NO_EXCEPTIONS
230 throw error();
231 #else
232 assert(0);
233 #endif
237 private:
239 luabind::functor<void>* m_func;
240 Tuple m_args;
241 mutable bool m_called;
245 } // detail
247 template<class Ret>
248 class functor
250 public:
252 functor(lua_State* L, const char* name) : L_(L)
254 lua_pushstring(L, name);
255 lua_gettable(L, LUA_GLOBALSINDEX);
256 ref_ = detail::ref(L);
259 functor()
260 : L_(0)
261 , ref_(LUA_NOREF)
265 functor(const functor<Ret>& obj): L_(obj.L_)
267 lua_getref(L_, obj.ref_);
268 ref_ = detail::ref(L_);
271 ~functor()
273 if (ref_ != LUA_NOREF) detail::unref(L_, ref_);
276 // this is a safe substitute for an implicit converter to bool
277 typedef void (functor::*member_ptr)() const;
278 operator member_ptr() const
280 if (is_valid()) return &functor::dummy;
281 return 0;
284 const functor<Ret>& operator=(const functor<Ret>& rhs)
286 L_ = rhs.L_;
287 lua_getref(L_, rhs.ref_);
288 ref_ = detail::ref(L_);
289 return *this;
292 inline bool is_valid() const { return ref_ != LUA_NOREF; }
294 lua_State* lua_state() { return L_; }
295 void pushvalue() { lua_getref(L_, ref_); }
297 #define BOOST_PP_ITERATION_PARAMS_1 (4, (0, LUABIND_MAX_ARITY, <luabind/functor.hpp>, 1))
298 #include BOOST_PP_ITERATE()
300 // TODO: should be private
302 functor(lua_State* L, int ref)
303 : L_(L)
304 , ref_(ref)
308 private:
310 void dummy() const {}
312 lua_State* L_;
313 int ref_;
317 #endif // LUABIND_FUNCTOR_HPP_INCLUDED
319 #else
321 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
322 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
324 #if BOOST_PP_ITERATION() > 0
325 template<BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), class A)>
326 #endif
327 typename boost::mpl::if_<boost::is_void<Ret>
328 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
329 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type
330 operator()(BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_OPERATOR_PARAMS, _)) const
332 typedef boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> tuple_t;
333 #if BOOST_PP_ITERATION() == 0
334 tuple_t args;
335 #else
336 tuple_t args(BOOST_PP_ENUM_PARAMS(BOOST_PP_ITERATION(), &a));
337 #endif
339 typedef typename boost::mpl::if_<boost::is_void<Ret>
340 , luabind::detail::proxy_functor_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
341 , luabind::detail::proxy_functor_caller<Ret, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;
343 return proxy_type(const_cast<luabind::functor<Ret>*>(this), args);
346 #define LUABIND_TUPLE_PARAMS(z, n, data) const A##n *
347 #define LUABIND_OPERATOR_PARAMS(z, n, data) const A##n & a##n
349 #endif