00001 #ifndef toast_python_callback_hpp_INCLUDED
00002 #define toast_python_callback_hpp_INCLUDED
00003
00004 #include <iostream>
00005 #include <boost/python.hpp>
00006 #include <boost/type_traits.hpp>
00007 #include <boost/python/raw_function.hpp>
00008 #include <boost/mpl/bool.hpp>
00009 #include <boost/function.hpp>
00010 #include <boost/functional.hpp>
00011
00018 namespace toast { namespace python {
00019
00020 namespace detail {
00021
00022 template <typename ArgType>
00023 inline boost::python::object
00024 getobjhelper(ArgType a, boost::mpl::bool_<false> const & ,
00025 boost::mpl::bool_<false> const & )
00026 {
00027 return boost::python::object(a);
00028 }
00029
00030 template <typename ArgType>
00031 inline boost::python::object
00032 getobjhelper(ArgType a, boost::mpl::bool_<true> const & ,
00033 boost::mpl::bool_<false> const & )
00034 {
00035 return boost::python::object(boost::python::ptr(&a));
00036 }
00037
00038 template <typename ArgType>
00039 inline boost::python::object
00040 getobjhelper(ArgType a, boost::mpl::bool_<false> const & ,
00041 boost::mpl::bool_<true> const & )
00042 {
00043 return boost::python::object(boost::python::ptr(a));
00044 }
00045
00046 template <typename ArgType>
00047 inline boost::python::object getobject( ArgType a )
00048 {
00049 boost::python::object ret = getobjhelper<ArgType>(a,
00050 typename boost::is_reference<ArgType>::type(),
00051 typename boost::is_pointer<ArgType>::type());
00052 return ret;
00053
00054 }
00055
00056 inline PyObject* pyobject_call(boost::python::object& o,
00057 boost::python::tuple& args, boost::python::dict& kw)
00058 {
00059 PyObject *r = PyObject_Call(o.ptr(), args.ptr(), kw.ptr());
00060 if( !r )
00061 PyErr_Print();
00062 return r;
00063 }
00064
00065 inline PyObject* pyobject_call(boost::python::object& o,
00066 boost::python::list& args, boost::python::dict& kw)
00067 {
00068 boost::python::tuple newargs(args);
00069 return pyobject_call(o, newargs, kw);
00070 }
00071
00072 template <typename T_return>
00073 struct callpyobj0
00074 {
00075 static T_return
00076 call( boost::python::object o, boost::python::tuple args,
00077 boost::python::dict kw )
00078 {
00079 PyGILState_STATE state(PyGILState_Ensure());
00080 boost::python::object ret(pyobject_call(o, args, kw));
00081 T_return &x = boost::python::extract<T_return&>(ret);
00082 PyGILState_Release(state);
00083 return x;
00084 }
00085 };
00086
00087 template <>
00088 struct callpyobj0<void>
00089 {
00090 static void
00091 call( boost::python::object o, boost::python::tuple args,
00092 boost::python::dict kw )
00093 {
00094 PyGILState_STATE state(PyGILState_Ensure());
00095 pyobject_call(o, args, kw);
00096 PyGILState_Release(state);
00097 }
00098 };
00099
00100 template <typename T_return, typename T_arg1>
00101 struct callpyobj1
00102 {
00103 static T_return
00104 call( boost::python::object o, boost::python::tuple args,
00105 boost::python::dict kw, T_arg1 arg1 )
00106 {
00107 PyGILState_STATE state(PyGILState_Ensure());
00108 boost::python::list newargs;
00109 newargs.append( getobject<T_arg1>(arg1) );
00110 newargs.extend( boost::python::list(args) );
00111 boost::python::object ret(pyobject_call(o, newargs, kw));
00112 T_return &x = boost::python::extract<T_return&>(ret);
00113 PyGILState_Release(state);
00114 return x;
00115 }
00116 };
00117
00118 template <typename T_arg1>
00119 struct callpyobj1<void, T_arg1>
00120 {
00121 static void
00122 call( boost::python::object o, boost::python::tuple args,
00123 boost::python::dict kw, T_arg1 arg1 )
00124 {
00125 PyGILState_STATE state(PyGILState_Ensure());
00126 boost::python::list newargs;
00127 newargs.append( getobject<T_arg1>(arg1) );
00128 newargs.extend( boost::python::list(args) );
00129 pyobject_call(o, newargs, kw);
00130 PyGILState_Release(state);
00131 }
00132 };
00133
00134 template <typename T_return, typename T_arg1, typename T_arg2>
00135 struct callpyobj2
00136 {
00137 static T_return
00138 call( boost::python::object o, boost::python::tuple args,
00139 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2 )
00140 {
00141 PyGILState_STATE state(PyGILState_Ensure());
00142 boost::python::list newargs;
00143 newargs.append( getobject<T_arg1>(arg1) );
00144 newargs.append( getobject<T_arg2>(arg2) );
00145 newargs.extend( boost::python::list(args) );
00146 boost::python::object ret(pyobject_call(o, newargs, kw));
00147 T_return &x = boost::python::extract<T_return&>(ret);
00148 PyGILState_Release(state);
00149 return x;
00150 }
00151 };
00152
00153 template <typename T_arg1, typename T_arg2>
00154 struct callpyobj2<void, T_arg1, T_arg2>
00155 {
00156 static void
00157 call( boost::python::object o, boost::python::tuple args,
00158 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2 )
00159 {
00160 PyGILState_STATE state(PyGILState_Ensure());
00161 boost::python::list newargs;
00162 newargs.append( getobject<T_arg1>(arg1) );
00163 newargs.append( getobject<T_arg2>(arg2) );
00164 newargs.extend( boost::python::list(args) );
00165 pyobject_call(o, newargs, kw);
00166 PyGILState_Release(state);
00167 }
00168 };
00169
00170 template <typename T_return, typename T_arg1, typename T_arg2,
00171 typename T_arg3>
00172 struct callpyobj3
00173 {
00174 static T_return
00175 call( boost::python::object o, boost::python::tuple args,
00176 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3 )
00177 {
00178 PyGILState_STATE state(PyGILState_Ensure());
00179 boost::python::list newargs;
00180 newargs.append( getobject<T_arg1>(arg1) );
00181 newargs.append( getobject<T_arg2>(arg2) );
00182 newargs.append( getobject<T_arg3>(arg3) );
00183 newargs.extend( boost::python::list(args) );
00184 boost::python::object ret(pyobject_call(o, newargs, kw));
00185 T_return &x = boost::python::extract<T_return&>(ret);
00186 PyGILState_Release(state);
00187 return x;
00188 }
00189 };
00190
00191 template <typename T_arg1, typename T_arg2, typename T_arg3>
00192 struct callpyobj3<void, T_arg1, T_arg2, T_arg3>
00193 {
00194 static void
00195 call( boost::python::object o, boost::python::tuple args,
00196 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3 )
00197 {
00198 PyGILState_STATE state(PyGILState_Ensure());
00199 boost::python::list newargs;
00200 newargs.append( getobject<T_arg1>(arg1) );
00201 newargs.append( getobject<T_arg2>(arg2) );
00202 newargs.append( getobject<T_arg3>(arg3) );
00203 newargs.extend( boost::python::list(args) );
00204 pyobject_call(o, newargs, kw);
00205 PyGILState_Release(state);
00206 }
00207 };
00208
00209 template <typename T_return, typename T_arg1, typename T_arg2,
00210 typename T_arg3, typename T_arg4>
00211 struct callpyobj4
00212 {
00213 static T_return
00214 call( boost::python::object o, boost::python::tuple args,
00215 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00216 T_arg4 arg4 )
00217 {
00218 PyGILState_STATE state(PyGILState_Ensure());
00219 boost::python::list newargs;
00220 newargs.append( getobject<T_arg1>(arg1) );
00221 newargs.append( getobject<T_arg2>(arg2) );
00222 newargs.append( getobject<T_arg3>(arg3) );
00223 newargs.append( getobject<T_arg4>(arg4) );
00224 newargs.extend( boost::python::list(args) );
00225 boost::python::object ret(pyobject_call(o, newargs, kw));
00226 T_return &x = boost::python::extract<T_return&>(ret);
00227 PyGILState_Release(state);
00228 return x;
00229 }
00230 };
00231
00232 template <typename T_arg1, typename T_arg2, typename T_arg3,
00233 typename T_arg4>
00234 struct callpyobj4<void, T_arg1, T_arg2, T_arg3, T_arg4 >
00235 {
00236 static void
00237 call( boost::python::object o, boost::python::tuple args,
00238 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00239 T_arg4 arg4 )
00240 {
00241 PyGILState_STATE state(PyGILState_Ensure());
00242 boost::python::list newargs;
00243 newargs.append( getobject<T_arg1>(arg1) );
00244 newargs.append( getobject<T_arg2>(arg2) );
00245 newargs.append( getobject<T_arg3>(arg3) );
00246 newargs.append( getobject<T_arg4>(arg4) );
00247 newargs.extend( boost::python::list(args) );
00248 pyobject_call(o, newargs, kw);
00249 PyGILState_Release(state);
00250 }
00251 };
00252
00253 template <typename T_return, typename T_arg1, typename T_arg2,
00254 typename T_arg3, typename T_arg4, typename T_arg5>
00255 struct callpyobj5
00256 {
00257 static T_return
00258 call( boost::python::object o, boost::python::tuple args,
00259 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00260 T_arg4 arg4, T_arg5 arg5 )
00261 {
00262 PyGILState_STATE state(PyGILState_Ensure());
00263 boost::python::list newargs;
00264 newargs.append( getobject<T_arg1>(arg1) );
00265 newargs.append( getobject<T_arg2>(arg2) );
00266 newargs.append( getobject<T_arg3>(arg3) );
00267 newargs.append( getobject<T_arg4>(arg4) );
00268 newargs.append( getobject<T_arg5>(arg5) );
00269 newargs.extend( boost::python::list(args) );
00270 boost::python::object ret(pyobject_call(o, newargs, kw));
00271 T_return &x = boost::python::extract<T_return&>(ret);
00272 PyGILState_Release(state);
00273 return x;
00274 }
00275 };
00276
00277 template <typename T_arg1, typename T_arg2, typename T_arg3,
00278 typename T_arg4, typename T_arg5>
00279 struct callpyobj5<void, T_arg1, T_arg2, T_arg3, T_arg4, T_arg5>
00280 {
00281 static void
00282 call( boost::python::object o, boost::python::tuple args,
00283 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00284 T_arg4 arg4, T_arg5 arg5 )
00285 {
00286 PyGILState_STATE state(PyGILState_Ensure());
00287 boost::python::list newargs;
00288 newargs.append( getobject<T_arg1>(arg1) );
00289 newargs.append( getobject<T_arg2>(arg2) );
00290 newargs.append( getobject<T_arg3>(arg3) );
00291 newargs.append( getobject<T_arg4>(arg4) );
00292 newargs.append( getobject<T_arg5>(arg5) );
00293 newargs.extend( boost::python::list(args) );
00294 pyobject_call(o, newargs, kw);
00295 PyGILState_Release(state);
00296 }
00297 };
00298
00299 template <typename T_return, typename T_arg1, typename T_arg2,
00300 typename T_arg3, typename T_arg4, typename T_arg5,
00301 typename T_arg6>
00302 struct callpyobj6
00303 {
00304 static T_return
00305 call( boost::python::object o, boost::python::tuple args,
00306 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00307 T_arg4 arg4, T_arg5 arg5, T_arg6 arg6 )
00308 {
00309 PyGILState_STATE state(PyGILState_Ensure());
00310 boost::python::list newargs;
00311 newargs.append( getobject<T_arg1>(arg1) );
00312 newargs.append( getobject<T_arg2>(arg2) );
00313 newargs.append( getobject<T_arg3>(arg3) );
00314 newargs.append( getobject<T_arg4>(arg4) );
00315 newargs.append( getobject<T_arg5>(arg5) );
00316 newargs.append( getobject<T_arg6>(arg6) );
00317 newargs.extend( boost::python::list(args) );
00318 boost::python::object ret(pyobject_call(o, newargs, kw));
00319 T_return &x = boost::python::extract<T_return&>(ret);
00320 PyGILState_Release(state);
00321 return x;
00322 }
00323 };
00324
00325 template <typename T_arg1, typename T_arg2, typename T_arg3,
00326 typename T_arg4, typename T_arg5, typename T_arg6>
00327 struct callpyobj6<void, T_arg1, T_arg2, T_arg3, T_arg4, T_arg5, T_arg6>
00328 {
00329 static void
00330 call( boost::python::object o, boost::python::tuple args,
00331 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00332 T_arg4 arg4, T_arg5 arg5, T_arg6 arg6 )
00333 {
00334 PyGILState_STATE state(PyGILState_Ensure());
00335 boost::python::list newargs;
00336 newargs.append( getobject<T_arg1>(arg1) );
00337 newargs.append( getobject<T_arg2>(arg2) );
00338 newargs.append( getobject<T_arg3>(arg3) );
00339 newargs.append( getobject<T_arg4>(arg4) );
00340 newargs.append( getobject<T_arg5>(arg5) );
00341 newargs.append( getobject<T_arg6>(arg6) );
00342 newargs.extend( boost::python::list(args) );
00343 pyobject_call(o, newargs, kw);
00344 PyGILState_Release(state);
00345 }
00346 };
00347
00348 template <typename T_return, typename T_arg1, typename T_arg2,
00349 typename T_arg3, typename T_arg4, typename T_arg5,
00350 typename T_arg6, typename T_arg7>
00351 struct callpyobj7
00352 {
00353 static T_return
00354 call( boost::python::object o, boost::python::tuple args,
00355 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00356 T_arg4 arg4, T_arg5 arg5, T_arg6 arg6, T_arg7 arg7 )
00357 {
00358 PyGILState_STATE state(PyGILState_Ensure());
00359 boost::python::list newargs;
00360 newargs.append( getobject<T_arg1>(arg1) );
00361 newargs.append( getobject<T_arg2>(arg2) );
00362 newargs.append( getobject<T_arg3>(arg3) );
00363 newargs.append( getobject<T_arg4>(arg4) );
00364 newargs.append( getobject<T_arg5>(arg5) );
00365 newargs.append( getobject<T_arg6>(arg6) );
00366 newargs.append( getobject<T_arg7>(arg7) );
00367 newargs.extend( boost::python::list(args) );
00368 boost::python::object ret(pyobject_call(o, newargs, kw));
00369 T_return &x = boost::python::extract<T_return&>(ret);
00370 PyGILState_Release(state);
00371 return x;
00372 }
00373 };
00374
00375 template <typename T_arg1, typename T_arg2, typename T_arg3,
00376 typename T_arg4, typename T_arg5, typename T_arg6,
00377 typename T_arg7>
00378 struct callpyobj7<void, T_arg1, T_arg2, T_arg3, T_arg4, T_arg5, T_arg6,
00379 T_arg7>
00380 {
00381 static void
00382 call( boost::python::object o, boost::python::tuple args,
00383 boost::python::dict kw, T_arg1 arg1, T_arg2 arg2, T_arg3 arg3,
00384 T_arg4 arg4, T_arg5 arg5, T_arg6 arg6, T_arg7 arg7 )
00385 {
00386 PyGILState_STATE state(PyGILState_Ensure());
00387 boost::python::list newargs;
00388 newargs.append( getobject<T_arg1>(arg1) );
00389 newargs.append( getobject<T_arg2>(arg2) );
00390 newargs.append( getobject<T_arg3>(arg3) );
00391 newargs.append( getobject<T_arg4>(arg4) );
00392 newargs.append( getobject<T_arg5>(arg5) );
00393 newargs.append( getobject<T_arg6>(arg6) );
00394 newargs.append( getobject<T_arg7>(arg7) );
00395 newargs.extend( boost::python::list(args) );
00396 pyobject_call(o, newargs, kw);
00397 PyGILState_Release(state);
00398 }
00399 };
00400
00401 template <int, typename Signature, typename Connection, typename T,
00402 typename Slot>
00403 struct connector;
00404
00405 template <typename Signature, typename Connection, typename T,
00406 typename Slot>
00407 struct connector<0, Signature, Connection, T, Slot>
00408 {
00409 static Connection
00410 connect( boost::python::tuple args, boost::python::dict kw,
00411 Connection (T::*f)(Slot) )
00412 {
00413 using namespace boost;
00414 using namespace boost::python;
00415 typedef function_traits<Signature> traits;
00416
00417 object xobj = args[0];
00418 T& x = extract<T&>(xobj);
00419 object callable = args[1];
00420 return (x.*f)(bind(callpyobj0<typename traits::result_type>::call,
00421 callable, boost::python::tuple(args.slice(2, _)),
00422 kw));
00423 }
00424 };
00425
00426 template <typename Signature, typename Connection, typename T,
00427 typename Slot>
00428 struct connector<1, Signature, Connection, T, Slot>
00429 {
00430 static Connection
00431 connect( boost::python::tuple args, boost::python::dict kw,
00432 Connection (T::*f)(Slot) )
00433 {
00434 using namespace boost;
00435 using namespace boost::python;
00436 typedef function_traits<Signature> traits;
00437
00438 object xobj = args[0];
00439 T& x = extract<T&>(xobj);
00440 object callable = args[1];
00441 return (x.*f)(bind(callpyobj1<typename traits::result_type,
00442 typename traits::arg1_type>::call,
00443 callable, boost::python::tuple(args.slice(2, _)),
00444 kw, _1) );
00445 }
00446 };
00447
00448 template <typename Signature, typename Connection, typename T,
00449 typename Slot>
00450 struct connector<2, Signature, Connection, T, Slot>
00451 {
00452 static Connection
00453 connect( boost::python::tuple args, boost::python::dict kw,
00454 Connection (T::*f)(Slot) )
00455 {
00456 using namespace boost;
00457 using namespace boost::python;
00458 typedef function_traits<Signature> traits;
00459
00460 object xobj = args[0];
00461 T& x = extract<T&>(xobj);
00462 object callable = args[1];
00463 return (x.*f)(bind(callpyobj2<typename traits::result_type,
00464 typename traits::arg1_type,
00465 typename traits::arg2_type>::call,
00466 callable, boost::python::tuple(args.slice(2, _)),
00467 kw, _1, _2));
00468 }
00469 };
00470
00471 template <typename Signature, typename Connection, typename T,
00472 typename Slot>
00473 struct connector<3, Signature, Connection, T, Slot>
00474 {
00475 static Connection
00476 connect( boost::python::tuple args, boost::python::dict kw,
00477 Connection (T::*f)(Slot) )
00478 {
00479 using namespace boost;
00480 using namespace boost::python;
00481 typedef function_traits<Signature> traits;
00482
00483 object xobj = args[0];
00484 T& x = extract<T&>(xobj);
00485 object callable = args[1];
00486 return (x.*f)(bind(callpyobj3<typename traits::result_type,
00487 typename traits::arg1_type,
00488 typename traits::arg2_type,
00489 typename traits::arg3_type>::call,
00490 callable, boost::python::tuple(args.slice(2, _)),
00491 kw, _1, _2, _3) );
00492 }
00493 };
00494
00495 template <typename Signature, typename Connection, typename T,
00496 typename Slot>
00497 struct connector<4, Signature, Connection, T, Slot>
00498 {
00499 static Connection
00500 connect( boost::python::tuple args, boost::python::dict kw,
00501 Connection (T::*f)(Slot) )
00502 {
00503 using namespace boost;
00504 using namespace boost::python;
00505 typedef function_traits<Signature> traits;
00506
00507 object xobj = args[0];
00508 T& x = extract<T&>(xobj);
00509 object callable = args[1];
00510 return (x.*f)(bind(callpyobj4<typename traits::result_type,
00511 typename traits::arg1_type,
00512 typename traits::arg2_type,
00513 typename traits::arg3_type,
00514 typename traits::arg4_type>::call,
00515 callable, boost::python::tuple(args.slice(2, _)),
00516 kw, _1, _2, _3, _4) );
00517 }
00518 };
00519
00520 template <typename Signature, typename Connection, typename T,
00521 typename Slot>
00522 struct connector<5, Signature, Connection, T, Slot>
00523 {
00524 static Connection
00525 connect( boost::python::tuple args, boost::python::dict kw,
00526 Connection (T::*f)(Slot) )
00527 {
00528 using namespace boost;
00529 using namespace boost::python;
00530 typedef function_traits<Signature> traits;
00531
00532 object xobj = args[0];
00533 T& x = extract<T&>(xobj);
00534 object callable = args[1];
00535 return (x.*f)(bind(callpyobj5<typename traits::result_type,
00536 typename traits::arg1_type,
00537 typename traits::arg2_type,
00538 typename traits::arg3_type,
00539 typename traits::arg4_type,
00540 typename traits::arg5_type>::call,
00541 callable, boost::python::tuple(args.slice(2, _)),
00542 kw, _1, _2, _3, _4, _5) );
00543 }
00544 };
00545
00546 template <typename Signature, typename Connection, typename T,
00547 typename Slot>
00548 struct connector<6, Signature, Connection, T, Slot>
00549 {
00550 static Connection
00551 connect( boost::python::tuple args, boost::python::dict kw,
00552 Connection (T::*f)(Slot) )
00553 {
00554 using namespace boost;
00555 using namespace boost::python;
00556 typedef function_traits<Signature> traits;
00557
00558 object xobj = args[0];
00559 T& x = extract<T&>(xobj);
00560 object callable = args[1];
00561 return (x.*f)(bind(callpyobj6<typename traits::result_type,
00562 typename traits::arg1_type,
00563 typename traits::arg2_type,
00564 typename traits::arg3_type,
00565 typename traits::arg4_type,
00566 typename traits::arg5_type,
00567 typename traits::arg6_type>::call,
00568 callable, boost::python::tuple(args.slice(2, _)),
00569 kw, _1, _2, _3, _4, _5, _6) );
00570 }
00571 };
00572
00573 template <typename Signature, typename Connection, typename T,
00574 typename Slot>
00575 struct connector<7, Signature, Connection, T, Slot>
00576 {
00577 static Connection
00578 connect( boost::python::tuple args, boost::python::dict kw,
00579 Connection (T::*f)(Slot) )
00580 {
00581 using namespace boost;
00582 using namespace boost::python;
00583 typedef function_traits<Signature> traits;
00584
00585 object xobj = args[0];
00586 T& x = extract<T&>(xobj);
00587 object callable = args[1];
00588 return (x.*f)(bind(callpyobj7<typename traits::result_type,
00589 typename traits::arg1_type,
00590 typename traits::arg2_type,
00591 typename traits::arg3_type,
00592 typename traits::arg4_type,
00593 typename traits::arg5_type,
00594 typename traits::arg6_type,
00595 typename traits::arg7_type>::call,
00596 callable, boost::python::tuple(args.slice(2, _)),
00597 kw, _1, _2, _3, _4, _5, _6, _7) );
00598 }
00599 };
00600
00601 }
00602
00629 template <typename Signature, typename Connection, typename T,
00630 typename Slot>
00631 boost::python::object signal_connect( Connection (T::*f) (Slot) )
00632 {
00633 using namespace boost;
00634 using namespace boost::python;
00635
00636 return
00637 raw_function(function<Connection (boost::python::tuple, dict)>
00638 (bind(&detail::connector<function_traits<Signature>::arity,
00639 Signature, Connection, T, Slot>::connect,
00640 _1, _2, f)) );
00641 }
00642
00645 }
00646
00647 }
00648
00658 #endif // toast_python_callback_hpp_INCLUDED