sigslot.i 29.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*
 * Module providing SWIG wrappers for sigslot that make it possible to use Lua functions as slots.
 *
 * SWIG's lua_fnptr extension and one of the structures it defines, SWIGLUA_REF, are used to handle
 * Lua functions on the C++ side.
 */

%module sigslot

%include lua_fnptr.i

%{
13
14
#include <cstdio>
#include <iostream>
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "tbb/recursive_mutex.h"
#include "ext/sigslot/sigslot.h"
%}


%inline {
namespace sigslot {

    /**
     * Signal arguments need to be wrapped before they can be passed to slots defined in Lua. That
     * requires the textual representation of their respective types to be known. Unfortunately,
     * there is no portable way to get a string describing a type in C++, and SWIG doesn't expose
     * such functionality. Consequently, we use a trait for that purpose; it needs to be specialised
     * for all types used as arguments of signals that are exposed to Lua, e.g.:
     *
     * template<>
     * struct LuaConnectionArgTraits<campvis::AbstractProcessor*> {
     *     static const char* const typeName;
     * };
     *
     * const char* const LuaConnectionArgTraits<campvis::AbstractProcessor*>::typeName = "campvis::AbstractProcessor *";
     */
    template<typename T>
    struct LuaConnectionArgTraits {};

    /*
     * Type bundling all information necessary to inject a signal argument into a Lua state:
     * a pointer to the argument and its corresponding SWIG type information.
     */
    typedef std::pair<void*, swig_type_info*> ArgWithTypeInfoType;

    /*
     * Return an object bundling the provided argument with its SWIG type information.
     */
    template<typename T>
    inline ArgWithTypeInfoType getArgWithTypeInfo(T arg) {
        const char* const typeName = LuaConnectionArgTraits<T>::typeName;
        swig_type_info* typeInfo = SWIG_TypeQuery(typeName);

        if (typeInfo == nullptr) {
            std::cerr << "SWIG wrapper for " << typeName << " not found" << std::endl;
        }

        return std::make_pair(arg, typeInfo);
    }

    /*
     * Prepend a new element to a list of objects that bundle arguments with their SWIG type
     * information and return the resulting list.
     */
    inline std::list<ArgWithTypeInfoType>* argWithTypeInfoListCons(ArgWithTypeInfoType head,
                                                                   std::list<ArgWithTypeInfoType>* tail)
    {
        if (head.second == nullptr) {
            delete tail;
        } else if (tail != nullptr) {
            tail->push_front(head);
            return tail;
        }

        return nullptr;
    }

    /*
     * Series of functions that take several arguments and return a list of objects that bundle
     * those arguments with their SWIG type information.
     */

    template<typename T>
    inline std::list<ArgWithTypeInfoType>* getArgWithTypeInfoList(T arg) {
        return argWithTypeInfoListCons(getArgWithTypeInfo<T>(arg), new std::list<ArgWithTypeInfoType>());
    }

    template<typename T1, typename T2>
    inline std::list<ArgWithTypeInfoType>* getArgWithTypeInfoList(T1 arg1, T2 arg2) {
        return argWithTypeInfoListCons(getArgWithTypeInfo<T1>(arg1), getArgWithTypeInfoList<T2>(arg2));
    }

    template<typename T1, typename T2, typename T3>
    inline std::list<ArgWithTypeInfoType>* getArgWithTypeInfoList(T1 arg1, T2 arg2, T3 arg3) {
        return argWithTypeInfoListCons(getArgWithTypeInfo<T1>(arg1), getArgWithTypeInfoList<T2, T3>(arg2, arg3));
    }

    template<typename T1, typename T2, typename T3, typename T4>
    inline std::list<ArgWithTypeInfoType>* getArgWithTypeInfoList(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
        return argWithTypeInfoListCons(getArgWithTypeInfo<T1>(arg1),
                                       getArgWithTypeInfoList<T2, T3, T4>(arg2, arg3, arg4));
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5>
    inline std::list<ArgWithTypeInfoType>* getArgWithTypeInfoList(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) {
        return argWithTypeInfoListCons(getArgWithTypeInfo<T1>(arg1),
                                       getArgWithTypeInfoList<T2, T3, T4, T5>(arg2, arg3, arg4, arg5));
    }

    // Type of mutex used to guard access to Lua state. See LuaVmState for more details.
    typedef tbb::recursive_mutex LuaStateMutexType;

    /*
     * Base class for Lua connections for specific signal arities.
     *
     * This class implements the bridging between sigslot's signals and slots defined in Lua, as
     * well as some other logic (e.g. copySlotFunction and getDummyDest) common to all Lua
     * connections. Subclasses need simply to call the helpers provided by this class from their
     * interface implementation methods.
120
121
122
123
     *
     * The template parameter is just a dummy parameter to enforce that _connection_base0 is always
     * locally instantiated as template and not linked into the sigslot library. This makes writing
     * scripting bindings much easier
124
     */
125
    template<int DUMMY_PARAMETER = 0>
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    class _lua_connection_base {
    public:
        _lua_connection_base(SWIGLUA_REF slot_fn)
            : _slot_fn(slot_fn)
            , _dummy_dest(nullptr)
        {
            // Retrieve from the registry the mutex associated with the function's Lua state
            lua_pushlightuserdata(slot_fn.L, static_cast<void*>(slot_fn.L));
            lua_gettable(slot_fn.L, LUA_REGISTRYINDEX);

            // The mutex should be stored as light userdata
            assert(lua_islightuserdata(slot_fn.L, -1));
            _lua_state_mutex = static_cast<LuaStateMutexType*>(lua_touserdata(slot_fn.L, -1));
            lua_pop(slot_fn.L, 1);
        }

        _lua_connection_base(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
            : _slot_fn(slot_fn)
            , _dummy_dest(nullptr)
            , _lua_state_mutex(lua_state_mutex)
        {}

        virtual ~_lua_connection_base() {
            swiglua_ref_clear(&_slot_fn);

            if (_dummy_dest != nullptr)
                delete _dummy_dest;
        }

        /**
         * Check if this connection's slot function is the same as the given Lua function.
         *
         * @param slot_fn reference to a Lua function acting as a slot
         * @return true if this connection wraps the given Lua function, false otherwise
         */
        bool wrapsSlotFunction(SWIGLUA_REF slot_fn) {
            if (slot_fn.L != _slot_fn.L)
                return false;

            swiglua_ref_get(&_slot_fn);
            swiglua_ref_get(&slot_fn);

            bool result = lua_rawequal(slot_fn.L, -1, -2) == 1;
            lua_pop(_slot_fn.L, 2);

            return result;
        }

    protected:
        /**
         * Return a copy of this connection's slot function.
         *
         * @return copy of this connection's slot function
         */
        SWIGLUA_REF copySlotFunction() {
            SWIGLUA_REF slot_fn;

            {
                LuaStateMutexType::scoped_lock lock(*_lua_state_mutex);

                swiglua_ref_get(&_slot_fn);
                swiglua_ref_set(&slot_fn, _slot_fn.L, -1);
                lua_pop(_slot_fn.L, 1);
            }

            return slot_fn;
        }

        /**
         * Return a dummy destination object.
         *
         * Because Lua connections do not have any destination objects (i.e. slots defined in Lua
         * are not attached to any class), a dummy one has to be created to comply with sigslot's
         * API.
         *
         * @return dummy destination object
         */
203
        has_slots* getDummyDest() const {
204
            if (_dummy_dest == nullptr)
205
                _dummy_dest = new has_slots();
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

            return _dummy_dest;
        }

        /**
         * Call a slot defined in Lua with the provided arguments.
         *
         * @param argWithTypeInfoList list of objects that bundle signal arguments with their SWIG
         *                            type information
         */
        void callLuaSlot(std::list<ArgWithTypeInfoType>* argWithTypeInfoList) {
            /*
             * argWithTypeInfoList is null if type information for some arguments could not be
             * found. In that case an error has been logged already and there's no processing left
             * to be done.
             */
            if (argWithTypeInfoList != nullptr) {
                LuaStateMutexType::scoped_lock lock(*_lua_state_mutex);

                // Put this connection's slot and all arguments on Lua's stack
                swiglua_ref_get(&_slot_fn);

                for (auto it = argWithTypeInfoList->begin(); it != argWithTypeInfoList->end(); ++it)
                    SWIG_NewPointerObj(_slot_fn.L, it->first, it->second, 0);

                if (lua_pcall(_slot_fn.L, argWithTypeInfoList->size(), 0, 0) != LUA_OK) {
                    const char* errorMsg = lua_tostring(_slot_fn.L, -1);

                    if (errorMsg == nullptr)
                        std::cerr << "(error object is not a string)" << std::endl;
                    else
                        std::cerr << "An error occured while calling a Lua slot function: " << errorMsg << std::endl;

                    lua_pop(_slot_fn.L, 1);
                }

                delete argWithTypeInfoList;
            }
        }

        SWIGLUA_REF _slot_fn;                          ///< Reference to a Lua function acting as a slot
247
        mutable has_slots* _dummy_dest;                ///< Dummy destination object needed to support getdest()
248
249
250
251
252
        LuaStateMutexType* _lua_state_mutex;           ///< Mutex guarding access to the above function's Lua state
    };

    /**
     * Custom signal-slot connection type for nullary signals that accepts Lua functions as slots.
253
254
255
256
     *
     * The template parameter is just a dummy parameter to enforce that _connection_base0 is always
     * locally instantiated as template and not linked into the sigslot library. This makes writing
     * scripting bindings much easier
257
     */
258
259
    template<int DUMMY_PARAMETER = 0>
    class _lua_connection0 : public _lua_connection_base<>, public _connection_base0
260
261
262
    {
    public:
        _lua_connection0(SWIGLUA_REF slot_fn)
263
            : _lua_connection_base<>(slot_fn)
264
265
266
        {}

        _lua_connection0(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
267
            : _lua_connection_base<>(slot_fn, lua_state_mutex)
268
269
        {}

270
271
        virtual _connection_base0* clone() {
            return new _lua_connection0<DUMMY_PARAMETER>(this->copySlotFunction(), this->_lua_state_mutex);
272
273
        }

274
        virtual _connection_base0* duplicate(sigslot::has_slots* pnewdest) {
275
276
277
278
279
280
281
282
            /*
             * Because Lua connections do not have any external destination objects that could be
             * copied (which in turn would require duplicating the connections for the copy), this
             * method should never be invoked.
             */
            return nullptr;
        }

283
        virtual void processSignal() {
284
            std::list<ArgWithTypeInfoType>* argWithTypeInfoList = new std::list<ArgWithTypeInfoType>(0);
285
            this->callLuaSlot(argWithTypeInfoList);
286
287
        }

288
        virtual has_slots* getdest() const {
289
            return this->getDummyDest();
290
291
292
293
294
295
        }
    };

    /**
     * Custom signal-slot connection type for unary signals that accepts Lua functions as slots.
     */
296
297
    template<class arg1_type>
    class _lua_connection1 : public _lua_connection_base<>, public _connection_base1<arg1_type>
298
299
300
    {
    public:
        _lua_connection1(SWIGLUA_REF slot_fn)
301
            : _lua_connection_base<>(slot_fn)
302
303
304
        {}

        _lua_connection1(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
305
            : _lua_connection_base<>(slot_fn, lua_state_mutex)
306
307
        {}

308
        virtual _connection_base1<arg1_type>* clone() {
309
            return new _lua_connection1(this->copySlotFunction(), this->_lua_state_mutex);
310
311
        }

312
        virtual _connection_base1<arg1_type>* duplicate(sigslot::has_slots* pnewdest) {
313
314
315
316
317
318
319
320
            /*
             * Because Lua connections do not have any external destination objects that could be
             * copied (which in turn would require duplicating the connections for the copy), this
             * method should never be invoked.
             */
            return nullptr;
        }

321
        virtual void processSignal(arg1_type a1) {
322
            std::list<ArgWithTypeInfoType>* argWithTypeInfoList = getArgWithTypeInfoList<arg1_type>(a1);
323
            this->callLuaSlot(argWithTypeInfoList);
324
325
        }

326
        virtual has_slots* getdest() const {
327
            return this->getDummyDest();
328
329
330
331
332
333
        }
    };

    /**
     * Custom signal-slot connection type for binary signals that accepts Lua functions as slots.
     */
334
335
336
    template<class arg1_type, class arg2_type>
    class _lua_connection2 : public _lua_connection_base<>
                           , public _connection_base2<arg1_type, arg2_type>
337
338
339
    {
    public:
        _lua_connection2(SWIGLUA_REF slot_fn)
340
            : _lua_connection_base<>(slot_fn)
341
342
343
        {}

        _lua_connection2(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
344
            : _lua_connection_base<>(slot_fn, lua_state_mutex)
345
346
        {}

347
        virtual _connection_base2<arg1_type, arg2_type>* clone() {
348
            return new _lua_connection2(this->copySlotFunction(), this->_lua_state_mutex);
349
350
        }

351
        virtual _connection_base2<arg1_type, arg2_type>* duplicate(sigslot::has_slots* pnewdest) {
352
353
354
355
356
357
358
359
            /*
             * Because Lua connections do not have any external destination objects that could be
             * copied (which in turn would require duplicating the connections for the copy), this
             * method should never be invoked.
             */
            return nullptr;
        }

360
        virtual void processSignal(arg1_type a1, arg2_type a2) {
361
            std::list<ArgWithTypeInfoType>* argWithTypeInfoList = getArgWithTypeInfoList<arg1_type, arg2_type>(a1, a2);
362
            this->callLuaSlot(argWithTypeInfoList);
363
364
        }

365
        virtual has_slots* getdest() const {
366
            return this->getDummyDest();
367
368
369
370
371
372
        }
    };

    /**
     * Custom signal-slot connection type for ternary signals that accepts Lua functions as slots.
     */
373
374
375
    template<class arg1_type, class arg2_type, class arg3_type>
    class _lua_connection3 : public _lua_connection_base<>
                           , public _connection_base3<arg1_type, arg2_type, arg3_type>
376
377
378
    {
    public:
        _lua_connection3(SWIGLUA_REF slot_fn)
379
            : _lua_connection_base<>(slot_fn)
380
381
382
        {}

        _lua_connection3(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
383
            : _lua_connection_base<>(slot_fn, lua_state_mutex)
384
385
        {}

386
        virtual _connection_base3<arg1_type, arg2_type, arg3_type>* clone() {
387
            return new _lua_connection3(this->copySlotFunction(), this->_lua_state_mutex);
388
389
        }

390
        virtual _connection_base3<arg1_type, arg2_type, arg3_type>* duplicate(sigslot::has_slots* pnewdest)
391
392
393
394
395
396
397
398
399
        {
            /*
             * Because Lua connections do not have any external destination objects that could be
             * copied (which in turn would require duplicating the connections for the copy), this
             * method should never be invoked.
             */
            return nullptr;
        }

400
        virtual void processSignal(arg1_type a1, arg2_type a2, arg3_type a3) {
401
402
            std::list<ArgWithTypeInfoType>* argWithTypeInfoList =
                    getArgWithTypeInfoList<arg1_type, arg2_type, arg3_type>(a1, a2, a3);
403
            this->callLuaSlot(argWithTypeInfoList);
404
405
        }

406
        virtual has_slots* getdest() const {
407
            return this->getDummyDest();
408
409
410
411
412
413
        }
    };

    /**
     * Custom signal-slot connection type for 4-ary signals that accepts Lua functions as slots.
     */
414
415
416
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type>
    class _lua_connection4 : public _lua_connection_base<>
                           , public _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type>
417
418
419
    {
    public:
        _lua_connection4(SWIGLUA_REF slot_fn)
420
            : _lua_connection_base<>(slot_fn)
421
422
423
        {}

        _lua_connection4(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
424
            : _lua_connection_base<>(slot_fn, lua_state_mutex)
425
426
        {}

427
        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type>* clone() {
428
            return new _lua_connection4(this->copySlotFunction(), this->_lua_state_mutex);
429
430
        }

431
        virtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type>* duplicate(sigslot::has_slots* pnewdest)
432
433
434
435
436
437
438
439
440
        {
            /*
             * Because Lua connections do not have any external destination objects that could be
             * copied (which in turn would require duplicating the connections for the copy), this
             * method should never be invoked.
             */
            return nullptr;
        }

441
        virtual void processSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) {
442
443
            std::list<ArgWithTypeInfoType>* argWithTypeInfoList =
                    getArgWithTypeInfoList<arg1_type, arg2_type, arg3_type, arg4_type>(a1, a2, a3, a4);
444
            this->callLuaSlot(argWithTypeInfoList);
445
446
        }

447
        virtual has_slots* getdest() const {
448
            return this->getDummyDest();
449
450
451
452
453
454
        }
    };

    /**
     * Custom signal-slot connection type for 5-ary signals that accepts Lua functions as slots.
     */
455
456
457
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
    class _lua_connection5 : public _lua_connection_base<>
                           , public _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>
458
459
460
    {
    public:
        _lua_connection5(SWIGLUA_REF slot_fn)
461
            : _lua_connection_base<>(slot_fn)
462
463
464
        {}

        _lua_connection5(SWIGLUA_REF slot_fn, LuaStateMutexType* lua_state_mutex)
465
            : _lua_connection_base<>(slot_fn, lua_state_mutex)
466
467
        {}

468
        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>* clone() {
469
            return new _lua_connection5(this->copySlotFunction(), this->_lua_state_mutex);
470
471
        }

472
        virtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>* duplicate(sigslot::has_slots* pnewdest)
473
474
475
476
477
478
479
480
481
        {
            /*
             * Because Lua connections do not have any external destination objects that could be
             * copied (which in turn would require duplicating the connections for the copy), this
             * method should never be invoked.
             */
            return nullptr;
        }

482
        virtual void processSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) {
483
484
            std::list<ArgWithTypeInfoType>* argWithTypeInfoList =
                    getArgWithTypeInfoList<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>(a1, a2, a3, a4, a5);
485
            this->callLuaSlot(argWithTypeInfoList);
486
487
        }

488
        virtual has_slots* getdest() const {
489
            return this->getDummyDest();
490
491
492
493
494
495
496
497
498
499
500
        }
    };

}
}

namespace sigslot {

    class signal0 {
    public:
        signal0();
501
502
        signal0(const sigslot::signal0& s);
        virtual ~signal0();
503
504
505
506
507
508
509
510

        %extend {
            /**
             * Connect this signal to a Lua function.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void connect(SWIGLUA_REF slot_fn) {
511
                sigslot::_lua_connection0<>* conn = new sigslot::_lua_connection0<>(slot_fn);
512
513
514
515
516
517
518
519
520
                $self->m_connected_slots.push_back(conn);
            }

            /**
             * Disconnect a Lua function from this signal.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void disconnect(SWIGLUA_REF slot_fn) {
521
                typedef sigslot::_signal_base0::connections_list connections_list;
522
523
524
525
                connections_list::iterator it = $self->m_connected_slots.begin();
                connections_list::iterator itEnd = $self->m_connected_slots.end();

                while (it != itEnd) {
526
527
                    sigslot::_lua_connection0<>* lua_connection =
                            dynamic_cast<sigslot::_lua_connection0<>*>(*it);
528
529
530
531
532
533
534
535
536
537
538
539
540

                    if (lua_connection != nullptr && lua_connection->wrapsSlotFunction(slot_fn)) {
                        delete lua_connection;
                        $self->m_connected_slots.erase(it);
                        return;
                    }

                    ++it;
                }
            }
        }
    };

541
    template<class arg1_type>
542
543
544
    class signal1 {
    public:
        signal1();
545
546
        signal1(const sigslot::signal1<arg1_type>& s);
        virtual ~signal1();
547
548
549
550
551
552
553
554

        %extend {
            /**
             * Connect this signal to a Lua function.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void connect(SWIGLUA_REF slot_fn) {
555
556
                sigslot::_lua_connection1<arg1_type>* conn =
                    new sigslot::_lua_connection1<arg1_type>(slot_fn);
557
558
559
560
561
562
563
564
565
                $self->m_connected_slots.push_back(conn);
            }

            /**
             * Disconnect a Lua function from this signal.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void disconnect(SWIGLUA_REF slot_fn) {
566
                typedef sigslot::_signal_base1<arg1_type>::connections_list connections_list;
567
568
569
570
571

                connections_list::iterator it = $self->m_connected_slots.begin();
                connections_list::iterator itEnd = $self->m_connected_slots.end();

                while (it != itEnd) {
572
573
                    sigslot::_lua_connection1<arg1_type>* lua_connection =
                            dynamic_cast<sigslot::_lua_connection1<arg1_type>*>(*it);
574
575
576
577
578
579
580
581
582
583
584
585
586

                    if (lua_connection != nullptr && lua_connection->wrapsSlotFunction(slot_fn)) {
                        delete lua_connection;
                        $self->m_connected_slots.erase(it);
                        return;
                    }

                    ++it;
                }
            }
        }
    };

587
    template<class arg1_type, class arg2_type>
588
589
590
    class signal2 {
    public:
        signal2();
591
592
        signal2(const sigslot::signal2<arg1_type, arg2_type>& s);
        virtual ~signal2();
593
594
595
596
597
598
599
600

        %extend {
            /**
             * Connect this signal to a Lua function.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void connect(SWIGLUA_REF slot_fn) {
601
602
                sigslot::_lua_connection2<arg1_type, arg2_type>* conn =
                    new sigslot::_lua_connection2<arg1_type, arg2_type>(slot_fn);
603
604
605
606
607
608
609
610
611
                $self->m_connected_slots.push_back(conn);
            }

            /**
             * Disconnect a Lua function from this signal.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void disconnect(SWIGLUA_REF slot_fn) {
612
                typedef sigslot::_signal_base2<arg1_type, arg2_type>::connections_list connections_list;
613
614
615
616
                connections_list::iterator it = $self->m_connected_slots.begin();
                connections_list::iterator itEnd = $self->m_connected_slots.end();

                while (it != itEnd) {
617
618
                    sigslot::_lua_connection2<arg1_type, arg2_type>* lua_connection =
                            dynamic_cast<sigslot::_lua_connection2<arg1_type, arg2_type>*>(*it);
619
620
621
622
623
624
625
626
627
628
629
630
631

                    if (lua_connection != nullptr && lua_connection->wrapsSlotFunction(slot_fn)) {
                        delete lua_connection;
                        $self->m_connected_slots.erase(it);
                        return;
                    }

                    ++it;
                }
            }
        }
    };

632
    template<class arg1_type, class arg2_type, class arg3_type>
633
634
635
    class signal3 {
    public:
        signal3();
636
637
        signal3(const sigslot::signal3<arg1_type, arg2_type, arg3_type>& s);
        virtual ~signal3();
638
639
640
641
642
643
644
645

        %extend {
            /**
             * Connect this signal to a Lua function.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void connect(SWIGLUA_REF slot_fn) {
646
647
                sigslot::_lua_connection3<arg1_type, arg2_type, arg3_type>* conn =
                    new sigslot::_lua_connection3<arg1_type, arg2_type, arg3_type>(slot_fn);
648
649
650
651
652
653
654
655
656
                $self->m_connected_slots.push_back(conn);
            }

            /**
             * Disconnect a Lua function from this signal.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void disconnect(SWIGLUA_REF slot_fn) {
657
                typedef sigslot::_signal_base3<arg1_type, arg2_type, arg3_type>::connections_list connections_list;
658
659
660
661
                connections_list::iterator it = $self->m_connected_slots.begin();
                connections_list::iterator itEnd = $self->m_connected_slots.end();

                while (it != itEnd) {
662
663
                    sigslot::_lua_connection3<arg1_type, arg2_type, arg3_type>* lua_connection =
                            dynamic_cast<sigslot::_lua_connection3<arg1_type, arg2_type, arg3_type>*>(*it);
664
665
666
667
668
669
670
671
672
673
674
675
676

                    if (lua_connection != nullptr && lua_connection->wrapsSlotFunction(slot_fn)) {
                        delete lua_connection;
                        $self->m_connected_slots.erase(it);
                        return;
                    }

                    ++it;
                }
            }
        }
    };

677
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type>
678
679
680
    class signal4 {
    public:
        signal4();
681
682
        signal4(const sigslot::signal4<arg1_type, arg2_type, arg3_type, arg4_type>& s);
        virtual ~signal4();
683
684
685
686
687
688
689
690

        %extend {
            /**
             * Connect this signal to a Lua function.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void connect(SWIGLUA_REF slot_fn) {
691
692
                sigslot::_lua_connection4<arg1_type, arg2_type, arg3_type, arg4_type>* conn =
                    new sigslot::_lua_connection4<arg1_type, arg2_type, arg3_type, arg4_type>(slot_fn);
693
694
695
696
697
698
699
700
701
                $self->m_connected_slots.push_back(conn);
            }

            /**
             * Disconnect a Lua function from this signal.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void disconnect(SWIGLUA_REF slot_fn) {
702
                typedef sigslot::_signal_base4<arg1_type, arg2_type, arg3_type, arg4_type>::connections_list connections_list;
703
704
705
706
                connections_list::iterator it = $self->m_connected_slots.begin();
                connections_list::iterator itEnd = $self->m_connected_slots.end();

                while (it != itEnd) {
707
708
                    sigslot::_lua_connection4<arg1_type, arg2_type, arg3_type, arg4_type>* lua_connection =
                            dynamic_cast<sigslot::_lua_connection4<arg1_type, arg2_type, arg3_type, arg4_type>*>(*it);
709
710
711
712
713
714
715
716
717
718
719
720
721

                    if (lua_connection != nullptr && lua_connection->wrapsSlotFunction(slot_fn)) {
                        delete lua_connection;
                        $self->m_connected_slots.erase(it);
                        return;
                    }

                    ++it;
                }
            }
        }
    };

722
    template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type>
723
724
725
    class signal5 {
    public:
        signal5();
726
727
        signal5(const sigslot::signal5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>& s);
        virtual ~signal5();
728
729
730
731
732
733
734
735

        %extend {
            /**
             * Connect this signal to a Lua function.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void connect(SWIGLUA_REF slot_fn) {
736
737
                sigslot::_lua_connection5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>* conn =
                    new sigslot::_lua_connection5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>(slot_fn);
738
739
740
741
742
743
744
745
746
                $self->m_connected_slots.push_back(conn);
            }

            /**
             * Disconnect a Lua function from this signal.
             *
             * @param slot_fn reference to a Lua function acting as a slot
             */
            void disconnect(SWIGLUA_REF slot_fn) {
747
                typedef sigslot::_signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>::connections_list connections_list;
748
749
750
751
                connections_list::iterator it = $self->m_connected_slots.begin();
                connections_list::iterator itEnd = $self->m_connected_slots.end();

                while (it != itEnd) {
752
                    sigslot::_lua_connection5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type>* lua_connection =
753
                            dynamic_cast<sigslot::_lua_connection5<arg1_type, arg2_type, arg3_type, arg4_type,
754
                                                                   arg5_type>*>(*it);
755
756
757
758
759
760
761
762
763
764
765
766
767

                    if (lua_connection != nullptr && lua_connection->wrapsSlotFunction(slot_fn)) {
                        delete lua_connection;
                        $self->m_connected_slots.erase(it);
                        return;
                    }

                    ++it;
                }
            }
        }
    };
}