forked from irods/irods_rule_engine_plugin_python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathirods_rule_engine_plugin-python.hpp
328 lines (292 loc) · 14.1 KB
/
irods_rule_engine_plugin-python.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
120
121
122
123
124
125
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
203
204
205
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#include <type_traits>
#include <functional>
#include "boost/any.hpp"
#include "boost/optional.hpp"
#include "boost/format.hpp"
#include "boost/core/demangle.hpp"
#include "irods_re_plugin.hpp"
#include "irods_exception.hpp"
#include <patchlevel.h>
#include <boost/version.hpp>
#pragma GCC diagnostic push
#if PY_VERSION_HEX < 0x030400A2
#pragma GCC diagnostic ignored "-Wregister"
#endif
#if PY_VERSION_HEX >= 0x03090000 && BOOST_VERSION < 107500
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include "boost/python.hpp"
#pragma GCC diagnostic pop
#include "irods_types.hpp"
#include "array_ref.hpp"
namespace bp = boost::python;
namespace boost {
namespace python {
stl_input_iterator<object> begin(const object& o) {
return stl_input_iterator<object>(o);
}
stl_input_iterator<object> end(const object&) {
return stl_input_iterator<object>();
}
}
}
template<typename T>
const char* getMsParamStringFromType();
template<>
const char* getMsParamStringFromType<genQueryInp_t>() { return GenQueryInp_MS_T; }
template<>
const char* getMsParamStringFromType<genQueryOut_t>() { return GenQueryOut_MS_T; }
template<>
const char* getMsParamStringFromType<keyValPair_t>() { return KeyValPair_MS_T; }
template<>
const char* getMsParamStringFromType<bytesBuf_t>() { return BUF_LEN_MS_T; }
template<>
const char* getMsParamStringFromType<fileLseekOut_t>() { return DataObjLseekOut_MS_T; }
template<>
const char* getMsParamStringFromType<rodsObjStat_t>() { return RodsObjStat_MS_T; }
template<>
const char* getMsParamStringFromType<int>() { return INT_MS_T; }
template<>
const char* getMsParamStringFromType<float>() { return FLOAT_MS_T; }
namespace {
boost::python::object object_from_msParam(msParam_t& msParam) {
if ( !msParam.inOutStruct ) {
return {};
} else if ( !msParam.type ) {
THROW(SYS_NOT_SUPPORTED, "msParam type is null");
} else if ( strcmp(msParam.type, GenQueryInp_MS_T) == 0 ) {
return boost::python::object{*static_cast<genQueryInp_t*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, GenQueryOut_MS_T) == 0 ) {
return boost::python::object{*static_cast<genQueryOut_t*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, KeyValPair_MS_T) == 0 ) {
return boost::python::object{*static_cast<keyValPair_t*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, DataObjLseekOut_MS_T) == 0 ) {
return boost::python::object{*static_cast<fileLseekOut_t*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, RodsObjStat_MS_T) == 0 ) {
return boost::python::object{*static_cast<rodsObjStat_t*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, INT_MS_T) == 0 ) {
return boost::python::object{*static_cast<int*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, FLOAT_MS_T) == 0 ) {
return boost::python::object{*static_cast<float*>(msParam.inOutStruct)};
} else if ( strcmp(msParam.type, BUF_LEN_MS_T) == 0 ) {
return msParam.inpOutBuf ?
boost::python::object{bytesBuf_t{msParam.inpOutBuf->len, msParam.inpOutBuf->buf}} :
boost::python::object{};
} else {
THROW(SYS_NOT_SUPPORTED, boost::format("Unknown type in msParam: [%s]") % msParam.type);
}
}
template<class T>
msParam_t msParam_from_object_impl(boost::python::object& obj) {
boost::python::extract<T&> extr{obj};
if (extr.check()) {
return {
.label=nullptr,
.type=strdup(getMsParamStringFromType<T>()),
.inOutStruct=&extr(),
.inpOutBuf=nullptr};
} else {
THROW(SYS_NOT_SUPPORTED, "Attempted to extract a boost::python::object containing a non-conforming type");
}
}
template<>
msParam_t msParam_from_object_impl<int>(boost::python::object& obj) {
boost::python::extract<int> extr{obj};
if (extr.check()) {
return {
.label=nullptr,
.type=strdup(getMsParamStringFromType<int>()),
.inOutStruct=new int{extr()},
.inpOutBuf=nullptr};
} else {
THROW(SYS_NOT_SUPPORTED, "Attempted to extract a boost::python::object containing a non-conforming type");
}
}
template<>
msParam_t msParam_from_object_impl<float>(boost::python::object& obj) {
boost::python::extract<float> extr{obj};
if (extr.check()) {
return {
.label=nullptr,
.type=strdup(getMsParamStringFromType<float>()),
.inOutStruct=new float{extr()},
.inpOutBuf=nullptr};
} else {
THROW(SYS_NOT_SUPPORTED, "Attempted to extract a boost::python::object containing a non-conforming type");
}
}
template<>
msParam_t msParam_from_object_impl<bytesBuf_t>(boost::python::object& obj) {
boost::python::extract<bytesBuf_t> extr{obj};
if (extr.check()) {
bytesBuf_t buf = extr();
return {
.label=nullptr,
.type=strdup(getMsParamStringFromType<bytesBuf_t>()),
.inOutStruct=new int{buf.len},
.inpOutBuf=new bytesBuf_t{buf}};
} else {
THROW(SYS_NOT_SUPPORTED, "Attempted to extract a boost::python::object containing a non-conforming type");
}
}
template<>
msParam_t msParam_from_object_impl<msParam_t>(boost::python::object& obj) {
boost::python::extract<msParam_t&> extr{obj};
if (extr.check()) {
return extr();
} else {
THROW(SYS_NOT_SUPPORTED, "Attempted to extract a boost::python::object containing a non-conforming type");
}
}
}
template<class T>
msParam_t msParam_from_object(boost::python::object& obj) {
return msParam_from_object_impl<T>(obj);
}
template<class T1, class T2, class... Ts>
msParam_t msParam_from_object(boost::python::object& obj) {
try {
return msParam_from_object_impl<T1>(obj);
} catch ( const irods::exception& ) {
return msParam_from_object<T2, Ts...>(obj);
}
}
//for value types
template<typename T,
typename std::enable_if_t<!std::is_pointer<T>{}>* = nullptr>
void update_argument_impl(boost::any& cpp_arg, boost::python::object& py_arg) {}
//for non-const single-pointer types
template<typename T,
typename std::enable_if_t<std::is_pointer<T>{}>* = nullptr,
typename std::enable_if_t<!std::is_const<std::remove_pointer_t<T>>{}>* = nullptr,
typename std::enable_if_t<!std::is_pointer<std::remove_pointer_t<T>>{}>* = nullptr>
void update_argument_impl(boost::any& cpp_arg, boost::python::object& py_arg) {
const boost::python::extract<std::remove_pointer_t<T>> py_arg_extracted{py_arg};
T cpp_arg_extracted = boost::any_cast<T>(cpp_arg);
if ( cpp_arg_extracted && py_arg_extracted.check() ) {
*cpp_arg_extracted = py_arg_extracted;
}
}
//for double-pointer types
template<typename T,
typename std::enable_if_t<std::is_pointer<T>{}>* = nullptr,
typename std::enable_if_t<std::is_pointer<std::remove_pointer_t<T>>{}>* = nullptr>
void update_argument_impl(boost::any& cpp_arg, boost::python::object& py_arg) {
const boost::python::extract<std::remove_pointer_t<std::remove_pointer_t<T>>> py_arg_extracted{py_arg};
T cpp_arg_extracted = boost::any_cast<T>(cpp_arg);
if ( cpp_arg_extracted && *cpp_arg_extracted && py_arg_extracted.check() ) {
**cpp_arg_extracted = py_arg_extracted;
}
}
//for const single-pointer types
template<typename T, typename std::enable_if_t<std::is_pointer<T>{}>* = nullptr, typename std::enable_if_t<std::is_const<std::remove_pointer_t<T>>{}>* = nullptr>
void update_argument_impl(boost::any& cpp_arg, boost::python::object& py_arg) {}
template<>
void update_argument_impl<const char*>(boost::any& cpp_arg, boost::python::object& py_arg) {}
template<>
void update_argument_impl<char*>(boost::any& cpp_arg, boost::python::object& py_arg) {
array_ref<char, true> py_string = boost::python::extract<array_ref<char, true>>{py_arg};
char * cpp_string = boost::any_cast<char*>(cpp_arg);
if ( cpp_string ) {
for ( int i = 0; cpp_string[i]; ++i ) {
cpp_string[i] = py_string[i];
}
}
}
template<>
void update_argument_impl<void*>(boost::any& cpp_arg, boost::python::object& py_arg) {}
//for value types
template<typename T, typename std::enable_if_t<!std::is_pointer<T>{}>* = nullptr>
boost::python::object object_from_specific(boost::any& arg) {
return boost::python::object{boost::any_cast<T&>(arg)};
}
//for single-pointer types
template<typename T,
typename std::enable_if_t<std::is_pointer<T>{}>* = nullptr,
typename std::enable_if_t<!std::is_pointer<std::remove_pointer_t<T>>{}>* = nullptr>
boost::python::object object_from_specific(boost::any& arg) {
T arg_extracted = boost::any_cast<T>(arg);
return arg_extracted ? boost::python::object{*arg_extracted} : boost::python::object{};
}
//for double-pointer types
template<typename T,
typename std::enable_if_t<std::is_pointer<T>{}>* = nullptr,
typename std::enable_if_t<std::is_pointer<std::remove_pointer_t<T>>{}>* = nullptr>
boost::python::object object_from_specific(boost::any& arg) {
T arg_extracted = boost::any_cast<T>(arg);
return arg_extracted && *arg_extracted ? boost::python::object{**arg_extracted} : boost::python::object{};
}
template<>
boost::python::object object_from_specific<const char*>(boost::any& arg) {
const char* str = boost::any_cast<const char*>(arg);
return str ? boost::python::object{std::string{str}} : boost::python::object{};
}
template<>
boost::python::object object_from_specific<char*>(boost::any& arg) {
char* str = boost::any_cast<char*>(arg);
return str ? boost::python::object{array_ref<char, true>{str}} : boost::python::object{};
}
template<>
boost::python::object object_from_specific<void*>(boost::any& arg) {
return boost::python::object{};
}
template<typename... Ts>
std::map<std::type_index, std::function<void(boost::any&, bp::object&)>> generate_update_argument_function_map(const type_sequence<Ts...>&) {
return {std::pair<std::type_index, std::function<void(boost::any&, bp::object&)>>{
std::type_index{typeid(Ts)}, std::function<void(boost::any&, bp::object&)>{&update_argument_impl<Ts>}}...,
std::pair<std::type_index, std::function<void(boost::any&, bp::object&)>>{
std::type_index{typeid(Ts*)}, std::function<void(boost::any&, bp::object&)>{&update_argument_impl<Ts*>}}...,
std::pair<std::type_index, std::function<void(boost::any&, bp::object&)>>{
std::type_index{typeid(const Ts*)}, std::function<void(boost::any&, bp::object&)>{&update_argument_impl<const Ts*>}}...,
std::pair<std::type_index, std::function<void(boost::any&, bp::object&)>>{
std::type_index{typeid(Ts**)}, std::function<void(boost::any&, bp::object&)>{&update_argument_impl<Ts**>}}...,
std::pair<std::type_index, std::function<void(boost::any&, bp::object&)>>{
std::type_index{typeid(void*)}, std::function<void(boost::any&, bp::object&)>{&update_argument_impl<void*>}}
};
}
template<typename... Ts>
std::map<std::type_index, std::function<bp::object(boost::any&)>> generate_object_from_any_function_map(const type_sequence<Ts...>&) {
return {std::pair<std::type_index, std::function<bp::object(boost::any&)>>{
std::type_index{typeid(Ts)}, std::function<bp::object(boost::any&)>{&object_from_specific<Ts>}}...,
std::pair<std::type_index, std::function<bp::object(boost::any&)>>{
std::type_index{typeid(Ts*)}, std::function<bp::object(boost::any&)>{&object_from_specific<Ts*>}}...,
std::pair<std::type_index, std::function<bp::object(boost::any&)>>{
std::type_index{typeid(const Ts*)}, std::function<bp::object(boost::any&)>{&object_from_specific<const Ts*>}}...,
std::pair<std::type_index, std::function<bp::object(boost::any&)>>{
std::type_index{typeid(Ts**)}, std::function<bp::object(boost::any&)>{&object_from_specific<Ts**>}}...,
std::pair<std::type_index, std::function<bp::object(boost::any&)>>{
std::type_index{typeid(void*)}, std::function<bp::object(boost::any&)>{&object_from_specific<void*>}}
};
}
void update_argument(boost::any& cpp_arg, boost::python::object& py_arg) {
static auto update_argument_function_map = generate_update_argument_function_map(list_of_irods_types{});
try {
return update_argument_function_map.at(std::type_index{cpp_arg.type()})(cpp_arg, py_arg);
} catch (const std::out_of_range&) {
//THROW(SYS_NOT_SUPPORTED, boost::format("Attempted to extract from a boost::python::object containing an unsupported type: %s") %
//boost::core::scoped_demangled_name{cpp_arg.type().name()}.get());
} catch (const boost::bad_any_cast&) {
THROW(SYS_NOT_SUPPORTED, "Failed any_cast when updating boost::any from boost:python::object");
}
}
boost::python::object object_from_any(boost::any& arg) {
static auto object_from_any_function_map = generate_object_from_any_function_map(list_of_irods_types{});
try {
return object_from_any_function_map.at(std::type_index{arg.type()})(arg);
} catch (const std::out_of_range&) {
std::map<std::string, std::string> arg_map{};
auto err = irods::re_serialization::serialize_parameter(arg, arg_map);
if ( err.ok() ) {
bp::dict arg_dict{};
for ( auto it = arg_map.begin(); it != arg_map.end(); ++it ) {
arg_dict[it->first] = it->second;
}
return arg_dict;
} else {
THROW(SYS_NOT_SUPPORTED, boost::format("Attempted to create a boost::python::object from a boost::any containing an unsupported type: %s") %
boost::core::scoped_demangled_name{arg.type().name()}.get());
}
} catch (const boost::bad_any_cast&) {
THROW(SYS_NOT_SUPPORTED, "Failed any_cast when creating boost:python::object from boost::any");
}
}