1 /**********************************************/
2 /* BEGIN interface for fold compound status   */
3 /* callback                                   */
4 /**********************************************/
5 
6 #ifdef SWIGPYTHON
7 %{
8 
9 #include <stdexcept>
10 
11 typedef struct {
12   PyObject  *cb;
13   PyObject  *data;
14   PyObject  *delete_data;
15 } pycallback_t;
16 
17 static void
18 py_wrap_fc_status_callback(unsigned char status,
19                            void          *data);
20 
21 static void
delete_pydata(pycallback_t * cb)22 delete_pydata(pycallback_t *cb)
23 {
24   if(cb->data != Py_None){
25     if(cb->delete_data != Py_None){
26       /* call user-defined data destructor */
27       PyObject *func, *arglist, *result, *err;
28       func = cb->delete_data;
29       arglist = Py_BuildValue("O", cb->data);
30       result  = PyObject_CallObject(func, arglist);
31 
32       /* BEGIN recognizing errors in callback execution */
33       if (result == NULL) {
34         if ((err = PyErr_Occurred())) {
35           /* print error message */
36           PyErr_Print();
37           /* we only treat TypeErrors differently here, as they indicate that the callback does not follow requirements! */
38           if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
39             throw std::runtime_error( "Fold compound delete_data() callback must take exactly 1 argument" );
40           } else {
41             throw std::runtime_error( "Some error occurred while executing fold compound delete_data() callback" );
42           }
43         }
44         PyErr_Clear();
45       }
46       /* END recognizing errors in callback execution */
47 
48       Py_DECREF(arglist);
49       Py_XDECREF(result);
50     }
51   }
52 
53   Py_DECREF(cb->data);
54   Py_DECREF(cb->delete_data);
55 }
56 
57 
58 static void
delete_pycallback(void * data)59 delete_pycallback(void * data)
60 {
61   pycallback_t *cb = (pycallback_t *)data;
62   /* first delete user data */
63   delete_pydata(cb);
64 
65   /* now dispose of the callback */
66   Py_DECREF(cb->cb);
67 
68   /* finally free pycallback */
69   free(cb);
70 }
71 
72 static void
fc_add_pycallback(vrna_fold_compound_t * vc,PyObject * PyFunc)73 fc_add_pycallback(vrna_fold_compound_t *vc,
74                   PyObject             *PyFunc)
75 {
76 
77   /* try to dispose of previous callback */
78   pycallback_t * cb;
79   if(vc->auxdata){
80     cb = (pycallback_t *)vc->auxdata;
81     /* release previous callback */
82     Py_XDECREF(cb->cb);
83   } else {
84     cb = (pycallback_t *)vrna_alloc(sizeof(pycallback_t));
85     Py_INCREF(Py_None);
86     cb->data = Py_None;
87 
88     Py_INCREF(Py_None);
89     cb->delete_data = Py_None;
90   }
91   cb->cb = PyFunc;    /* remember callback */
92   Py_XINCREF(PyFunc); /* Increase referenc counter */
93 
94   /* finaly bind callback wrapper to fold compound */
95   vc->auxdata = (void *)cb;
96   if(!vc->free_auxdata)
97     vc->free_auxdata = &delete_pycallback;
98 
99   vrna_fold_compound_add_callback(vc, &py_wrap_fc_status_callback);
100 }
101 
102 static void
fc_add_pydata(vrna_fold_compound_t * vc,PyObject * data,PyObject * PyFunc)103 fc_add_pydata(vrna_fold_compound_t *vc,
104               PyObject             *data,
105               PyObject             *PyFunc)
106 {
107 
108   pycallback_t * cb;
109   /* try to dispose of previous data */
110   if(vc->auxdata){
111     cb = (pycallback_t *)vc->auxdata;
112     delete_pydata(cb);
113   } else {
114     cb = (pycallback_t *)vrna_alloc(sizeof(pycallback_t));
115 
116     Py_INCREF(Py_None);
117     cb->cb = Py_None;
118   }
119   cb->data        = data;   /* remember data */
120   cb->delete_data = PyFunc; /* remember delete data function */
121 
122   /* increase reference counter */
123   Py_INCREF(data);
124   Py_INCREF(PyFunc);
125 
126   vc->auxdata = (void *)cb;
127   if(!vc->free_auxdata)
128     vc->free_auxdata = &delete_pycallback;
129 }
130 
131 static void
py_wrap_fc_status_callback(unsigned char status,void * data)132 py_wrap_fc_status_callback( unsigned char status,
133                             void          *data)
134 {
135 
136   PyObject *func, *arglist, *result, *err;
137   pycallback_t *cb = (pycallback_t *)data;
138 
139   func = cb->cb;
140   /* compose argument list */
141   arglist = Py_BuildValue("(B,O)", status, (cb->data) ? cb->data : Py_None);
142   result =  PyObject_CallObject(func, arglist);
143 
144   /* BEGIN recognizing errors in callback execution */
145   if (result == NULL) {
146     if ((err = PyErr_Occurred())) {
147       /* print error message */
148       PyErr_Print();
149       /* we only treat TypeErrors differently here, as they indicate that the callback does not follow requirements! */
150       if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
151         throw std::runtime_error( "Fold compound callback must take exactly 2 arguments" );
152       } else {
153         throw std::runtime_error( "Some error occurred while executing fold compound callback" );
154       }
155     }
156     PyErr_Clear();
157   }
158   /* END recognizing errors in callback execution */
159 
160   Py_DECREF(arglist);
161   Py_XDECREF(result);
162   return /*void*/;
163 }
164 
165 %}
166 
167 static void
168 fc_add_pycallback(vrna_fold_compound_t *vc,
169                   PyObject             *PyFunc);
170 
171 static void
172 fc_add_pydata(vrna_fold_compound_t *vc,
173               PyObject             *data,
174               PyObject             *PyFuncOrNone);
175 
176 /* now we bind the above functions as methods to the fold_compound object */
177 %extend vrna_fold_compound_t {
178 
179 %feature("autodoc") add_auxdata;
180 %feature("kwargs") add_auxdata;
181 %feature("autodoc") add_callback;
182 %feature("kwargs") add_callback;
183 
184   PyObject *
185   add_auxdata(PyObject *data,
186               PyObject *PyFuncOrNone = Py_None)
187   {
188     fc_add_pydata($self, data, PyFuncOrNone);
189     Py_RETURN_NONE;
190   }
191 
192   PyObject *
add_callback(PyObject * PyFunc)193   add_callback(PyObject *PyFunc)
194   {
195     fc_add_pycallback($self, PyFunc);
196     Py_RETURN_NONE;
197   }
198 }
199 
200 #endif
201